1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the linguist application of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
#include "qplatformdefs.h"
31
#include "translator.h"
33
#ifndef QT_NO_TRANSLATION
35
#include "qfileinfo.h"
37
#include "qcoreapplication.h"
38
#include "qdatastream.h"
41
#include "qalgorithms.h"
45
#if defined(Q_OS_UNIX)
49
// most of the headers below are already included in qplatformdefs.h
50
// also this lacks Large File support but that's probably irrelevant
51
#if defined(QT_USE_MMAP)
61
3cb86418caef9c95cd211cbf60a1bddd
65
// magic number for the file
66
static const int MagicLength = 16;
67
static const uchar magic[MagicLength] = {
68
0x3c, 0xb8, 0x64, 0x18, 0xca, 0xef, 0x9c, 0x95,
69
0xcd, 0x21, 0x1c, 0xbf, 0x60, 0xa1, 0xbd, 0xdd
72
static bool match(const char* found, const char* target)
74
// 0 means anything, "" means empty
75
return found == 0 || qstrcmp(found, target) == 0;
78
#if defined(Q_C_CALLBACKS)
83
Yes, unfortunately, we have code here that depends on endianness.
84
The candidate is big endian (it comes from a .qm file) whereas the
85
target endianness depends on the system Qt is running on.
88
static int __cdecl cmp_uint32_little(const void* target, const void* candidate)
90
static int cmp_uint32_little(const void* target, const void* candidate)
93
const uchar* t = (const uchar*) target;
94
const uchar* c = (const uchar*) candidate;
95
return t[3] != c[0] ? (int) t[3] - (int) c[0]
96
: t[2] != c[1] ? (int) t[2] - (int) c[1]
97
: t[1] != c[2] ? (int) t[1] - (int) c[2]
98
: (int) t[0] - (int) c[3];
102
static int __cdecl cmp_uint32_big(const void* target, const void* candidate)
104
static int cmp_uint32_big(const void* target, const void* candidate)
107
const uint* t = (const uint*) target;
108
const uint* c = (const uint*) candidate;
109
return (*t > *c ? 1 : (*t == *c ? 0 : -1));
112
#if defined(Q_C_CALLBACKS)
116
static uint elfHash(const char * name)
123
k = (const uchar *) name;
126
if ((g = (h & 0xf0000000)) != 0)
136
extern bool qt_detectRTLLanguage();
138
class TranslatorPrivate
144
Offset(const TranslatorMessage& m, int offset)
145
: h(m.hash()), o(offset) { }
147
bool operator<(const Offset &other) const {
148
return (h != other.h) ? h < other.h : o < other.o;
150
bool operator==(const Offset &other) const {
151
return h == other.h && o == other.o;
157
enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69 };
159
TranslatorPrivate(Translator *qq) : q(qq), unmapPointer(0), unmapLength(0) {}
160
// Translator must finalize this before deallocating it
163
// for mmap'ed files, this is what needs to be unmapped.
165
unsigned int unmapLength;
167
// for squeezed but non-file data, this is what needs to be deleted
168
QByteArray messageArray;
169
QByteArray offsetArray;
170
QByteArray contextArray;
172
#ifndef QT_NO_TRANSLATION_BUILDER
173
QMap<TranslatorMessage, void *> messages;
176
bool do_load(const uchar *data, int len);
184
\brief The Translator class provides internationalization support for text
191
An object of this class contains a set of TranslatorMessage
192
objects, each of which specifies a translation from a source
193
language to a target language. Translator provides functions to
194
look up translations, add new ones, remove them, load and save
197
The most common use of Translator is to: load a translator file
198
created with \l{Qt Linguist Manual}, install it using
199
QApplication::installTranslator(), and use it via QObject::tr().
203
int main(int argc, char ** argv)
205
QApplication app(argc, argv);
207
Translator translator(0);
208
translator.load("french.qm", ".");
209
app.installTranslator(&translator);
212
app.setMainWidget(&m);
218
Note that the translator must be created \e before the
219
application's main window.
221
Most applications will never need to do anything else with this
222
class. The other functions provided by this class are useful for
223
applications that work on translator files.
225
We call a translation a "messsage". For this reason, translation
226
files are sometimes referred to as "message files".
228
It is possible to lookup a translation using findMessage() (as
229
tr() and QApplication::translate() do) and contains(), to insert a
230
new translation messsage using insert(), and to remove one using
233
Translation tools often need more information than the bare source
234
text and translation, for example, context information to help
235
the translator. But end-user programs that are using translations
236
usually only need lookup. To cater for these different needs,
237
Translator can use stripped translator files that use the minimum
238
of memory and which support little more functionality than
241
Thus, load() may not load enough information to make anything more
242
than findMessage() work. save() has an argument indicating
243
whether to save just this minimum of information or to save
246
"Everything" means that for each translation item the following
250
\i The \e {translated text} - the return value from tr().
253
\i The \e {source text} - usually the argument to tr().
254
\i The \e context - usually the class name for the tr() caller.
255
\i The \e comment - a comment that helps disambiguate different uses
256
of the same text in the same context.
260
The minimum for each item is just the information necessary for
261
findMessage() to return the right text. This may include the
262
source, context and comment, but usually it is just a hash value
263
and the translated text.
265
For example, the "Cancel" in a dialog might have "Anuluj" when the
266
program runs in Polish (in this case the source text would be
267
"Cancel"). The context would (normally) be the dialog's class
268
name; there would normally be no comment, and the translated text
271
But it's not always so simple. The Spanish version of a printer
272
dialog with settings for two-sided printing and binding would
273
probably require both "Activado" and "Activada" as translations
274
for "Enabled". In this case the source text would be "Enabled" in
275
both cases, and the context would be the dialog's class name, but
276
the two items would have disambiguating comments such as
277
"two-sided printing" for one and "binding" for the other. The
278
comment enables the translator to choose the appropriate gender
279
for the Spanish version, and enables Qt to distinguish between
282
Note that when Translator loads a stripped file, most functions
283
do not work. The functions that do work with stripped files are
284
explicitly documented as such.
286
\sa TranslatorMessage QApplication::installTranslator()
287
QApplication::removeTranslator() QObject::tr() QApplication::translate()
291
\enum Translator::SaveMode
293
This enum type defines how Translator writes translation
294
files. There are two modes:
296
\value Everything files are saved with all available information
297
\value Stripped files are saved with just enough information for
298
end-user applications
300
Note that when Translator loads a stripped file, most functions do
301
not work. The functions that do work with stripped files are
302
explicitly documented as such.
306
Constructs an empty message file object with parent \a parent that
307
is not connected to any file.
310
Translator::Translator(QObject * parent)
311
: QTranslator(parent)
313
d = new TranslatorPrivate(this);
317
Destroys the object and frees any allocated resources.
320
Translator::~Translator()
322
if (QCoreApplication::instance())
323
QCoreApplication::instance()->removeTranslator(this);
329
Loads \a filename + \a suffix (".qm" if the \a suffix is
330
not specified), which may be an absolute file name or relative
331
to \a directory. The previous contents of this translator object
334
If the file name does not exist, other file names are tried
335
in the following order:
338
\i File name without \a suffix appended.
339
\i File name with text after a character in \a search_delimiters
340
stripped ("_." is the default for \a search_delimiters if it is
341
an empty string) and \a suffix.
342
\i File name stripped without \a suffix appended.
343
\i File name stripped further, etc.
346
For example, an application running in the fr_CA locale
347
(French-speaking Canada) might call load("foo.fr_ca",
348
"/opt/foolib"). load() would then try to open the first existing
349
readable file from this list:
352
\i /opt/foolib/foo.fr_ca.qm
353
\i /opt/foolib/foo.fr_ca
354
\i /opt/foolib/foo.fr.qm
355
\i /opt/foolib/foo.fr
356
\i /opt/foolib/foo.qm
363
bool Translator::load(const QString & filename, const QString & directory,
364
const QString & search_delimiters,
365
const QString & suffix)
371
if (filename[0] == QLatin1Char('/')
373
|| (filename[0].isLetter() && filename[1] == QLatin1Char(':')) || filename[0] == QLatin1Char('\\')
376
prefix = QLatin1String("");
380
if (prefix.length()) {
381
if (prefix[int(prefix.length()-1)] != QLatin1Char('/'))
382
prefix += QLatin1Char('/');
385
QString fname = filename;
388
delims = search_delimiters.isNull() ? QString::fromLatin1("_.") : search_delimiters;
393
realname = prefix + fname + (suffix.isNull() ? QString::fromLatin1(".qm") : suffix);
394
fi.setFile(realname);
398
realname = prefix + fname;
399
fi.setFile(realname);
404
for (int i = 0; i < (int)delims.length(); i++) {
405
int k = fname.lastIndexOf(delims[i]);
410
// no truncations? fail
414
fname.truncate(rightmost);
417
// realname is now the fully qualified name of a readable file.
427
#define MAP_FAILED -1
431
if (!realname.startsWith(QLatin1String(":")))
432
fd = QT_OPEN(QFile::encodeName(realname), O_RDONLY,
433
#if defined(Q_OS_WIN)
441
if (!fstat(fd, &st)) {
443
ptr = reinterpret_cast<char *>(
444
mmap(0, st.st_size, // any address, whole file
445
PROT_READ, // read-only memory
446
MAP_FILE | MAP_PRIVATE, // swap-backed map from file
447
fd, 0)); // from offset 0 of fd
448
if (ptr && ptr != reinterpret_cast<char *>(MAP_FAILED)) {
449
d->unmapPointer = ptr;
450
d->unmapLength = st.st_size;
456
#endif // QT_USE_MMAP
459
QFile file(realname);
462
d->unmapLength = file.size();
463
d->unmapPointer = new char[d->unmapLength];
465
if (file.open(QIODevice::ReadOnly))
466
ok = (d->unmapLength == (uint)file.read(d->unmapPointer, d->unmapLength));
469
delete [] d->unmapPointer;
476
return d->do_load(reinterpret_cast<const uchar *>(d->unmapPointer), d->unmapLength);
481
\fn bool Translator::load(const uchar *data, int len)
483
Loads the .qm file data \a data of length \a len into the
486
The data is not copied. The caller must be able to guarantee that \a data
487
will not be deleted or modified.
489
bool Translator::load(const uchar *data, int len)
492
return d->do_load(data, len);
495
bool TranslatorPrivate::do_load(const uchar *data, int len)
497
if (len < MagicLength || memcmp(data, magic, MagicLength) != 0) {
502
QByteArray array = QByteArray::fromRawData((const char *) data, len);
503
QDataStream s(&array, QIODevice::ReadOnly);
506
s.device()->seek(MagicLength);
509
quint32 blockLen = 0;
510
s >> tag >> blockLen;
511
while (tag && blockLen) {
512
if ((quint32) s.device()->pos() + blockLen > (quint32) len) {
517
if (tag == TranslatorPrivate::Contexts) {
518
contextArray = QByteArray(array.constData() + s.device()->pos(), blockLen);
519
} else if (tag == TranslatorPrivate::Hashes) {
520
offsetArray = QByteArray(array.constData() + s.device()->pos(), blockLen);
521
} else if (tag == TranslatorPrivate::Messages) {
522
messageArray = QByteArray(array.constData() + s.device()->pos(), blockLen);
525
if (!s.device()->seek(s.device()->pos() + blockLen)) {
532
s >> tag >> blockLen;
538
#ifndef QT_NO_TRANSLATION_BUILDER
541
Saves this message file to \a filename, overwriting the previous
542
contents of \a filename. If \a mode is \c Everything (the
543
default), all the information is preserved. If \a mode is \c
544
Stripped, any information that is not necessary for findMessage()
550
bool Translator::save(const QString & filename, SaveMode mode)
552
QFile file(filename);
553
if (file.open(QIODevice::WriteOnly)) {
556
QDataStream s(&file);
557
s.writeRawData((const char *)magic, MagicLength);
560
if (!d->offsetArray.isEmpty()) {
561
tag = (quint8)TranslatorPrivate::Hashes;
562
quint32 oas = (quint32)d->offsetArray.size();
564
s.writeRawData(d->offsetArray, oas);
566
if (!d->messageArray.isEmpty()) {
567
tag = (quint8)TranslatorPrivate::Messages;
568
quint32 mas = (quint32)d->messageArray.size();
570
s.writeRawData(d->messageArray, mas);
572
if (!d->contextArray.isEmpty()) {
573
tag = (quint8)TranslatorPrivate::Contexts;
574
quint32 cas = (quint32)d->contextArray.size();
576
s.writeRawData(d->contextArray, cas);
586
Empties this translator of all contents.
588
This function works with stripped translator files.
591
void Translator::clear()
593
if (d->unmapPointer && d->unmapLength) {
594
#if defined(QT_USE_MMAP)
595
munmap(d->unmapPointer, d->unmapLength);
597
delete [] d->unmapPointer;
603
d->messageArray.clear();
604
d->offsetArray.clear();
605
d->contextArray.clear();
606
#ifndef QT_NO_TRANSLATION_BUILDER
610
QEvent ev(QEvent::LanguageChange);
611
QCoreApplication::sendEvent(QCoreApplication::instance(), &ev);
614
#ifndef QT_NO_TRANSLATION_BUILDER
617
Converts this message file to the compact format used to store
618
message files on disk.
620
You should never need to call this directly; save() and other
621
functions call it as necessary. \a mode is for internal use.
623
\sa save() unsqueeze()
626
void Translator::squeeze(SaveMode mode)
628
if (d->messages.isEmpty()) {
629
if (mode == Stripped)
635
QMap<TranslatorMessage, void *> messages = d->messages;
638
QMap<TranslatorPrivate::Offset, void *> offsets;
640
QDataStream ms(&d->messageArray, QIODevice::WriteOnly);
641
QMap<TranslatorMessage, void *>::const_iterator it, next;
642
int cpPrev = 0, cpNext = 0;
643
for (it = messages.constBegin(); it != messages.constEnd(); ++it) {
647
if (next == messages.constEnd())
650
cpNext = (int) it.key().commonPrefix(next.key());
651
offsets.insert(TranslatorPrivate::Offset(it.key(), ms.device()->pos()), (void *)0);
652
it.key().write(ms, mode == Stripped, (TranslatorMessage::Prefix)qMax(cpPrev, cpNext + 1));
655
QMap<TranslatorPrivate::Offset, void *>::Iterator offset;
656
offset = offsets.begin();
657
QDataStream ds(&d->offsetArray, QIODevice::WriteOnly);
658
while (offset != offsets.end()) {
659
TranslatorPrivate::Offset k = offset.key();
661
ds << (quint32)k.h << (quint32)k.o;
664
if (mode == Stripped) {
665
QMap<QByteArray, int> contextSet;
666
for (it = messages.constBegin(); it != messages.constEnd(); ++it)
667
++contextSet[it.key().context()];
670
if (contextSet.size() < 200)
671
hTableSize = (contextSet.size() < 60) ? 151 : 503;
672
else if (contextSet.size() < 2500)
673
hTableSize = (contextSet.size() < 750) ? 1511 : 5003;
675
hTableSize = (contextSet.size() < 10000) ? 15013 : 3 * contextSet.size() / 2;
677
QMultiMap<int, const char *> hashMap;
678
QMap<QByteArray, int>::const_iterator c;
679
for (c = contextSet.constBegin(); c != contextSet.constEnd(); ++c)
680
hashMap.insert(elfHash(c.key()) % hTableSize, c.key());
683
The contexts found in this translator are stored in a hash
684
table to provide fast lookup. The context array has the
688
quint16 hTable[hTableSize];
689
quint8 contextPool[...];
691
The context pool stores the contexts as Pascal strings:
696
Let's consider the look-up of context "FunnyDialog". A
697
hash value between 0 and hTableSize - 1 is computed, say h.
698
If hTable[h] is 0, "FunnyDialog" is not covered by this
699
translator. Else, we check in the contextPool at offset
700
2 * hTable[h] to see if "FunnyDialog" is one of the
701
contexts stored there, until we find it or we meet the
704
d->contextArray.resize(2 + (hTableSize << 1));
705
QDataStream t(&d->contextArray, QIODevice::WriteOnly);
707
quint16 *hTable = new quint16[hTableSize];
708
memset(hTable, 0, hTableSize * sizeof(quint16));
711
t.device()->seek(2 + (hTableSize << 1));
712
t << (quint16)0; // the entry at offset 0 cannot be used
715
QMap<int, const char *>::const_iterator entry = hashMap.constBegin();
716
while (entry != hashMap.constEnd()) {
718
const char *con = entry.value();
719
hTable[i] = (quint16)(upto >> 1);
722
uint len = (uint)qstrlen(con);
723
len = qMin(len, 255u);
725
t.writeRawData(con, len);
728
} while (entry != hashMap.constEnd() && entry.key() == i);
730
t << (quint8) 0; // empty string
732
} while ((upto & 0x1) != 0); // offsets have to be even
735
for (int j = 0; j < hTableSize; j++)
740
qWarning("Translator::squeeze: Too many contexts");
741
d->contextArray.clear();
748
Converts this message file into an easily modifiable data
749
structure, less compact than the format used in the files.
751
You should never need to call this function; it is called by
752
insert() and friends as necessary.
757
void Translator::unsqueeze()
759
if (!d->messages.isEmpty() || d->messageArray.isEmpty())
762
QDataStream s(&d->messageArray, QIODevice::ReadOnly);
764
TranslatorMessage m(s);
767
d->messages.insert(m, (void *)0);
773
Returns true if this message file contains a message with the key
774
(\a context, \a sourceText, \a comment); otherwise returns false.
776
This function works with stripped translator files.
778
(This is is a one-liner that calls findMessage().)
781
bool Translator::contains(const char* context, const char* sourceText,
782
const char* comment) const
784
return !findMessage(context, sourceText, comment).translation().isNull();
789
Inserts \a message into this message file.
791
This function does \e not work with stripped translator files. It
792
may appear to, but that is not dependable.
797
void Translator::insert(const TranslatorMessage& message)
800
d->messages.remove(message); // safer
801
d->messages.insert(message, (void *) 0);
805
\fn void Translator::insert(const char *context, const char
806
*sourceText, const QString &translation)
810
Inserts the \a sourceText and \a translation into the translator
811
with the given \a context.
815
Removes \a message from this translator.
817
This function works with stripped translator files.
822
void Translator::remove(const TranslatorMessage& message)
825
d->messages.remove(message);
830
\fn void Translator::remove(const char *, const char *)
834
Removes the translation associated to the key (\a context, \a sourceText,
835
"") from this translator.
839
/*! Returns the TranslatorMessage for the key
840
(\a context, \a sourceText, \a comment). If none is found,
841
also tries (\a context, \a sourceText, "").
844
TranslatorMessage Translator::findMessage(const char *context, const char *sourceText,
845
const char *comment) const
854
#ifndef QT_NO_TRANSLATION_BUILDER
855
if (!d->messages.isEmpty()) {
856
QMap<TranslatorMessage, void *>::const_iterator it;
858
it = d->messages.find(TranslatorMessage(context, sourceText, comment));
859
if (it != d->messages.constEnd())
863
it = d->messages.find(TranslatorMessage(context, sourceText, ""));
864
if (it != d->messages.constEnd())
867
return TranslatorMessage();
871
if (d->offsetArray.isEmpty())
872
return TranslatorMessage();
875
Check if the context belongs to this Translator. If many
876
translators are installed, this step is necessary.
878
if (!d->contextArray.isEmpty()) {
879
quint16 hTableSize = 0;
880
QDataStream t(d->contextArray);
882
uint g = elfHash(context) % hTableSize;
883
t.device()->seek(2 + (g << 1));
887
return TranslatorMessage();
888
t.device()->seek(2 + (hTableSize << 1) + (off << 1));
895
return TranslatorMessage();
896
t.readRawData(con, len);
898
if (qstrcmp(con, context) == 0)
903
size_t numItems = d->offsetArray.size() / (2 * sizeof(quint32));
905
return TranslatorMessage();
908
quint32 h = elfHash(QByteArray(sourceText) + comment);
910
char *r = (char *) bsearch(&h, d->offsetArray, numItems,
912
(QSysInfo::ByteOrder == QSysInfo::BigEndian) ? cmp_uint32_big
913
: cmp_uint32_little);
915
// go back on equal key
916
while (r != d->offsetArray.constData() && cmp_uint32_big(r - 8, r) == 0)
919
QDataStream s(d->offsetArray);
920
s.device()->seek(r - d->offsetArray.constData());
925
QDataStream ms(d->messageArray);
927
ms.device()->seek(ro);
928
TranslatorMessage m(ms);
929
if (match(m.context(), context)
930
&& match(m.sourceText(), sourceText)
931
&& match(m.comment(), comment))
942
return TranslatorMessage();
946
Returns true if this translator is empty, otherwise returns false.
947
This function works with stripped and unstripped translation files.
949
bool Translator::isEmpty() const
951
return !d->unmapPointer && !d->unmapLength && d->messageArray.isEmpty() &&
952
d->offsetArray.isEmpty() && d->contextArray.isEmpty() && d->messages.isEmpty();
956
#ifndef QT_NO_TRANSLATION_BUILDER
959
Returns a list of the messages in the translator. This function is
960
rather slow. Because it is seldom called, it's optimized for
961
simplicity and small size, rather than speed.
963
If you want to iterate over the list, you should iterate over a
966
QList<TranslatorMessage> list = myTranslator.messages();
967
QList<TranslatorMessage>::Iterator it = list.begin();
968
while (it != list.end()) {
969
process_message(*it);
975
QList<TranslatorMessage> Translator::messages() const
977
((Translator *) this)->unsqueeze();
978
return d->messages.keys();
984
\class TranslatorMessage
986
\brief The TranslatorMessage class contains a translator message and its
992
This class is of no interest to most applications. It is useful
993
for translation tools such as \l{Qt Linguist Manual}{Qt Linguist}.
994
It is provided simply to make the API complete and regular.
996
For a Translator object, a lookup key is a triple (\e context, \e
997
{source text}, \e comment) that uniquely identifies a message. An
998
extended key is a quadruple (\e hash, \e context, \e {source
999
text}, \e comment), where \e hash is computed from the source text
1000
and the comment. Unless you plan to read and write messages
1001
yourself, you need not worry about the hash value.
1003
TranslatorMessage stores this triple or quadruple and the relevant
1004
translation if there is any.
1010
Constructs a translator message with the extended key (0, 0, 0, 0)
1011
and an empty string as translation.
1014
TranslatorMessage::TranslatorMessage()
1021
Constructs an translator message with the extended key (\e h, \a
1022
context, \a sourceText, \a comment), where \e h is computed from
1023
\a sourceText and \a comment, and possibly with a \a translation.
1026
TranslatorMessage::TranslatorMessage(const char * context,
1027
const char * sourceText,
1028
const char * comment,
1029
const QString& translation)
1030
: cx(context), st(sourceText), cm(comment), tn(translation)
1032
// 0 means we don't know, "" means empty
1033
if (cx == (const char*)0)
1035
if (st == (const char*)0)
1037
if (cm == (const char*)0)
1039
h = elfHash(st + cm);
1044
Constructs a translator message read from the \a stream. The
1045
resulting message may have any combination of content.
1047
\sa Translator::save()
1050
TranslatorMessage::TranslatorMessage(QDataStream & stream)
1059
if (!stream.atEnd())
1060
stream.readRawData(&tag, 1);
1064
h = elfHash(st + cm);
1066
case Tag_SourceText16: // obsolete
1068
st = str16.toLatin1();
1070
case Tag_Translation:
1073
case Tag_Context16: // obsolete
1075
cx = str16.toLatin1();
1080
case Tag_SourceText:
1085
if (cx.isEmpty()) // for compatibility
1091
case Tag_Obsolete1: // obsolete
1107
Constructs a copy of translator message \a m.
1110
TranslatorMessage::TranslatorMessage(const TranslatorMessage & m)
1111
: cx(m.cx), st(m.st), cm(m.cm), tn(m.tn)
1118
Assigns message \a m to this translator message and returns a
1119
reference to this translator message.
1122
TranslatorMessage & TranslatorMessage::operator=(
1123
const TranslatorMessage & m)
1135
\fn uint TranslatorMessage::hash() const
1137
Returns the hash value used internally to represent the lookup
1138
key. This value is zero only if this translator message was
1139
constructed from a stream containing invalid data.
1141
The hashing function is unspecified, but it will remain unchanged
1142
in future versions of Qt.
1146
\fn const char *TranslatorMessage::context() const
1148
Returns the context for this message (e.g. "MyDialog").
1152
\fn const char *TranslatorMessage::sourceText() const
1154
Returns the source text of this message (e.g. "&Save").
1158
\fn const char *TranslatorMessage::comment() const
1160
Returns the comment for this message (e.g. "File|Save").
1164
\fn void TranslatorMessage::setTranslation(const QString & translation)
1166
Sets the translation of the source text to \a translation.
1172
\fn QString TranslatorMessage::translation() const
1174
Returns the translation of the source text (e.g., "&Sauvegarder").
1176
\sa setTranslation()
1180
\enum TranslatorMessage::Prefix
1182
Let (\e h, \e c, \e s, \e m) be the extended key. The possible
1185
\value NoPrefix no prefix
1186
\value Hash only (\e h)
1187
\value HashContext only (\e h, \e c)
1188
\value HashContextSourceText only (\e h, \e c, \e s)
1189
\value HashContextSourceTextComment the whole extended key, (\e
1190
h, \e c, \e s, \e m)
1192
\sa write() commonPrefix()
1196
Writes this translator message to the \a stream. If \a strip is
1197
false (the default), all the information in the message is
1198
written. If \a strip is true, only the part of the extended key
1199
specified by \a prefix is written with the translation (\c
1200
HashContextSourceTextComment by default).
1205
void TranslatorMessage::write(QDataStream & stream, bool strip,
1206
Prefix prefix) const
1210
tag = (char)Tag_Translation;
1211
stream.writeRawData(&tag, 1);
1215
prefix = HashContextSourceTextComment;
1218
case HashContextSourceTextComment:
1219
tag = (char)Tag_Comment;
1220
stream.writeRawData(&tag, 1);
1223
case HashContextSourceText:
1224
tag = (char)Tag_SourceText;
1225
stream.writeRawData(&tag, 1);
1229
tag = (char)Tag_Context;
1230
stream.writeRawData(&tag, 1);
1234
tag = (char)Tag_Hash;
1235
stream.writeRawData(&tag, 1);
1239
tag = (char)Tag_End;
1240
stream.writeRawData(&tag, 1);
1245
Returns the widest lookup prefix that is common to this translator
1246
message and to message \a m.
1248
For example, if the extended key is for this message is (71,
1249
"PrintDialog", "Yes", "Print?") and that for \a m is (71,
1250
"PrintDialog", "No", "Print?"), this function returns \c
1256
TranslatorMessage::Prefix TranslatorMessage::commonPrefix(
1257
const TranslatorMessage& m) const
1266
return HashContextSourceText;
1267
return HashContextSourceTextComment;
1272
Returns true if the extended key of this object is equal to that of
1273
\a m; otherwise returns false.
1276
bool TranslatorMessage::operator==(const TranslatorMessage& m) const
1278
return h == m.h && cx == m.cx && st == m.st && cm == m.cm;
1283
\fn bool TranslatorMessage::operator!=(const TranslatorMessage& m) const
1285
Returns true if the extended key of this object is different from
1286
that of \a m; otherwise returns false.
1291
Returns true if the extended key of this object is
1292
lexicographically before than that of \a m; otherwise returns
1296
bool TranslatorMessage::operator<(const TranslatorMessage& m) const
1298
return h != m.h ? h < m.h
1299
: (cx != m.cx ? cx < m.cx
1300
: (st != m.st ? st < m.st : cm < m.cm));
1305
\fn bool TranslatorMessage::operator<=(const TranslatorMessage& m) const
1307
Returns true if the extended key of this object is
1308
lexicographically before that of \a m or if they are equal;
1309
otherwise returns false.
1313
\fn bool TranslatorMessage::operator>(const TranslatorMessage& m) const
1315
Returns true if the extended key of this object is
1316
lexicographically after that of \a m; otherwise returns false.
1320
\fn bool TranslatorMessage::operator>=(const TranslatorMessage& m) const
1322
Returns true if the extended key of this object is
1323
lexicographically after that of \a m or if they are equal;
1324
otherwise returns false.
1328
\fn QString Translator::find(const char *context, const char *sourceText, const char * comment) const
1330
Use findMessage() instead.
1333
#endif // QT_NO_TRANSLATION