source: trunk/tools/linguist/shared/translator.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 23.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the Qt Linguist of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "translator.h"
43
44#include "simtexth.h"
45
46#include <iostream>
47
48#include <stdio.h>
49#ifdef Q_OS_WIN
50// required for _setmode, to avoid _O_TEXT streams...
51# ifdef Q_OS_WINCE
52# include <stdlib.h>
53# else
54# include <io.h> // for _setmode
55# include <fcntl.h> // for _O_BINARY
56# endif
57#endif
58
59#include <QtCore/QDebug>
60#include <QtCore/QDir>
61#include <QtCore/QFile>
62#include <QtCore/QFileInfo>
63#include <QtCore/QTextCodec>
64#include <QtCore/QTextStream>
65
66#include <private/qtranslator_p.h>
67
68QT_BEGIN_NAMESPACE
69
70#ifdef QT_BOOTSTRAPPED
71QString QObject::tr(const char *sourceText, const char *, int n)
72{
73 QString ret = QString::fromLatin1(sourceText);
74 if (n >= 0)
75 ret.replace(QLatin1String("%n"), QString::number(n));
76 return ret;
77}
78#endif
79
80Translator::Translator() :
81 m_codec(QTextCodec::codecForName("ISO-8859-1")),
82 m_locationsType(AbsoluteLocations)
83{
84}
85
86void Translator::registerFileFormat(const FileFormat &format)
87{
88 //qDebug() << "Translator: Registering format " << format.extension;
89 QList<Translator::FileFormat> &formats = registeredFileFormats();
90 for (int i = 0; i < formats.size(); ++i)
91 if (format.fileType == formats[i].fileType && format.priority < formats[i].priority) {
92 formats.insert(i, format);
93 return;
94 }
95 formats.append(format);
96}
97
98QList<Translator::FileFormat> &Translator::registeredFileFormats()
99{
100 static QList<Translator::FileFormat> theFormats;
101 return theFormats;
102}
103
104void Translator::replaceSorted(const TranslatorMessage &msg)
105{
106 int index = find(msg);
107 if (index == -1)
108 appendSorted(msg);
109 else
110 m_messages[index] = msg;
111}
112
113void Translator::extend(const TranslatorMessage &msg)
114{
115 int index = find(msg);
116 if (index == -1) {
117 m_messages.append(msg);
118 } else {
119 TranslatorMessage &emsg = m_messages[index];
120 emsg.addReferenceUniq(msg.fileName(), msg.lineNumber());
121 if (!msg.extraComment().isEmpty()) {
122 QString cmt = emsg.extraComment();
123 if (!cmt.isEmpty())
124 cmt.append(QLatin1String("\n----------\n"));
125 cmt.append(msg.extraComment());
126 emsg.setExtraComment(cmt);
127 }
128 if (msg.isUtf8() != emsg.isUtf8()) {
129 emsg.setUtf8(true);
130 emsg.setNonUtf8(true);
131 }
132 }
133}
134
135void Translator::append(const TranslatorMessage &msg)
136{
137 m_messages.append(msg);
138}
139
140void Translator::appendSorted(const TranslatorMessage &msg)
141{
142 int msgLine = msg.lineNumber();
143 if (msgLine < 0) {
144 m_messages.append(msg);
145 return;
146 }
147
148 int bestIdx = 0; // Best insertion point found so far
149 int bestScore = 0; // Its category: 0 = no hit, 1 = pre or post, 2 = middle
150 int bestSize = 0; // The length of the region. Longer is better within one category.
151
152 // The insertion point to use should this region turn out to be the best one so far
153 int thisIdx = 0;
154 int thisScore = 0;
155 int thisSize = 0;
156 // Working vars
157 int prevLine = 0;
158 int curIdx = 0;
159 foreach (const TranslatorMessage &mit, m_messages) {
160 bool sameFile = mit.fileName() == msg.fileName() && mit.context() == msg.context();
161 int curLine;
162 if (sameFile && (curLine = mit.lineNumber()) >= prevLine) {
163 if (msgLine >= prevLine && msgLine < curLine) {
164 thisIdx = curIdx;
165 thisScore = thisSize ? 2 : 1;
166 }
167 ++thisSize;
168 prevLine = curLine;
169 } else {
170 if (thisSize) {
171 if (!thisScore) {
172 thisIdx = curIdx;
173 thisScore = 1;
174 }
175 if (thisScore > bestScore || (thisScore == bestScore && thisSize > bestSize)) {
176 bestIdx = thisIdx;
177 bestScore = thisScore;
178 bestSize = thisSize;
179 }
180 thisScore = 0;
181 thisSize = sameFile ? 1 : 0;
182 prevLine = 0;
183 }
184 }
185 ++curIdx;
186 }
187 if (thisSize && !thisScore) {
188 thisIdx = curIdx;
189 thisScore = 1;
190 }
191 if (thisScore > bestScore || (thisScore == bestScore && thisSize > bestSize))
192 m_messages.insert(thisIdx, msg);
193 else if (bestScore)
194 m_messages.insert(bestIdx, msg);
195 else
196 m_messages.append(msg);
197}
198
199static QString guessFormat(const QString &filename, const QString &format)
200{
201 if (format != QLatin1String("auto"))
202 return format;
203
204 foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) {
205 if (filename.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive))
206 return fmt.extension;
207 }
208
209 // the default format.
210 // FIXME: change to something more widely distributed later.
211 return QLatin1String("ts");
212}
213
214bool Translator::load(const QString &filename, ConversionData &cd, const QString &format)
215{
216 cd.m_sourceDir = QFileInfo(filename).absoluteDir();
217 cd.m_sourceFileName = filename;
218
219 QFile file;
220 if (filename.isEmpty() || filename == QLatin1String("-")) {
221#ifdef Q_OS_WIN
222 // QFile is broken for text files
223# ifdef Q_OS_WINCE
224 ::_setmode(stdin, _O_BINARY);
225# else
226 ::_setmode(0, _O_BINARY);
227# endif
228#endif
229 if (!file.open(stdin, QIODevice::ReadOnly)) {
230 cd.appendError(QString::fromLatin1("Cannot open stdin!? (%1)")
231 .arg(file.errorString()));
232 return false;
233 }
234 } else {
235 file.setFileName(filename);
236 if (!file.open(QIODevice::ReadOnly)) {
237 cd.appendError(QString::fromLatin1("Cannot open %1: %2")
238 .arg(filename, file.errorString()));
239 return false;
240 }
241 }
242
243 QString fmt = guessFormat(filename, format);
244
245 foreach (const FileFormat &format, registeredFileFormats()) {
246 if (fmt == format.extension) {
247 if (format.loader)
248 return (*format.loader)(*this, file, cd);
249 cd.appendError(QString(QLatin1String("No loader for format %1 found"))
250 .arg(fmt));
251 return false;
252 }
253 }
254
255 cd.appendError(QString(QLatin1String("Unknown format %1 for file %2"))
256 .arg(format, filename));
257 return false;
258}
259
260
261bool Translator::save(const QString &filename, ConversionData &cd, const QString &format) const
262{
263 QFile file;
264 if (filename.isEmpty() || filename == QLatin1String("-")) {
265#ifdef Q_OS_WIN
266 // QFile is broken for text files
267# ifdef Q_OS_WINCE
268 ::_setmode(stdout, _O_BINARY);
269# else
270 ::_setmode(1, _O_BINARY);
271# endif
272#endif
273 if (!file.open(stdout, QIODevice::WriteOnly)) {
274 cd.appendError(QString::fromLatin1("Cannot open stdout!? (%1)")
275 .arg(file.errorString()));
276 return false;
277 }
278 } else {
279 file.setFileName(filename);
280 if (!file.open(QIODevice::WriteOnly)) {
281 cd.appendError(QString::fromLatin1("Cannot create %1: %2")
282 .arg(filename, file.errorString()));
283 return false;
284 }
285 }
286
287 QString fmt = guessFormat(filename, format);
288 cd.m_targetDir = QFileInfo(filename).absoluteDir();
289
290 foreach (const FileFormat &format, registeredFileFormats()) {
291 if (fmt == format.extension) {
292 if (format.saver)
293 return (*format.saver)(*this, file, cd);
294 cd.appendError(QString(QLatin1String("Cannot save %1 files")).arg(fmt));
295 return false;
296 }
297 }
298
299 cd.appendError(QString(QLatin1String("Unknown format %1 for file %2"))
300 .arg(format).arg(filename));
301 return false;
302}
303
304QString Translator::makeLanguageCode(QLocale::Language language, QLocale::Country country)
305{
306 QLocale locale(language, country);
307 if (country == QLocale::AnyCountry) {
308 QString languageCode = locale.name().section(QLatin1Char('_'), 0, 0);
309 if (languageCode.length() <= 3)
310 return languageCode;
311 return QString();
312 } else {
313 return locale.name();
314 }
315}
316
317void Translator::languageAndCountry(const QString &languageCode,
318 QLocale::Language *lang, QLocale::Country *country)
319{
320 QLocale locale(languageCode);
321 if (lang)
322 *lang = locale.language();
323
324 if (country) {
325 if (languageCode.indexOf(QLatin1Char('_')) != -1)
326 *country = locale.country();
327 else
328 *country = QLocale::AnyCountry;
329 }
330}
331
332bool Translator::release(QFile *iod, ConversionData &cd) const
333{
334 foreach (const FileFormat &format, registeredFileFormats()) {
335 if (format.extension == QLatin1String("qm"))
336 return (*format.saver)(*this, *iod, cd);
337 }
338 cd.appendError(QLatin1String("No .qm saver available."));
339 return false;
340}
341
342int Translator::find(const TranslatorMessage &msg) const
343{
344 for (int i = 0; i < m_messages.count(); ++i) {
345 const TranslatorMessage &tmsg = m_messages.at(i);
346 if (msg.id().isEmpty() || tmsg.id().isEmpty()) {
347 if (msg.context() == tmsg.context()
348 && msg.sourceText() == tmsg.sourceText()
349 && msg.comment() == tmsg.comment())
350 return i;
351 } else {
352 if (msg.id() == tmsg.id())
353 return i;
354 }
355 }
356 return -1;
357}
358
359TranslatorMessage Translator::find(const QString &context,
360 const QString &comment, const TranslatorMessage::References &refs) const
361{
362 if (!refs.isEmpty()) {
363 for (TMM::ConstIterator it = m_messages.constBegin(); it != m_messages.constEnd(); ++it) {
364 if (it->context() == context && it->comment() == comment)
365 foreach (const TranslatorMessage::Reference &itref, it->allReferences())
366 foreach (const TranslatorMessage::Reference &ref, refs)
367 if (itref == ref)
368 return *it;
369 }
370 }
371 return TranslatorMessage();
372}
373
374bool Translator::contains(const QString &context) const
375{
376 foreach (const TranslatorMessage &msg, m_messages)
377 if (msg.context() == context && msg.sourceText().isEmpty() && msg.id().isEmpty())
378 return true;
379 return false;
380}
381
382TranslatorMessage Translator::find(const QString &context) const
383{
384 foreach (const TranslatorMessage &msg, m_messages)
385 if (msg.context() == context && msg.sourceText().isEmpty() && msg.id().isEmpty())
386 return msg;
387 return TranslatorMessage();
388}
389
390void Translator::stripObsoleteMessages()
391{
392 TMM newmm;
393 for (TMM::ConstIterator it = m_messages.begin(); it != m_messages.end(); ++it)
394 if (it->type() != TranslatorMessage::Obsolete)
395 newmm.append(*it);
396 m_messages = newmm;
397}
398
399void Translator::stripFinishedMessages()
400{
401 TMM newmm;
402 for (TMM::ConstIterator it = m_messages.begin(); it != m_messages.end(); ++it)
403 if (it->type() != TranslatorMessage::Finished)
404 newmm.append(*it);
405 m_messages = newmm;
406}
407
408void Translator::stripEmptyContexts()
409{
410 TMM newmm;
411 for (TMM::ConstIterator it = m_messages.begin(); it != m_messages.end(); ++it)
412 if (it->sourceText() != QLatin1String(ContextComment))
413 newmm.append(*it);
414 m_messages = newmm;
415}
416
417void Translator::stripNonPluralForms()
418{
419 TMM newmm;
420 for (TMM::ConstIterator it = m_messages.begin(); it != m_messages.end(); ++it)
421 if (it->isPlural())
422 newmm.append(*it);
423 m_messages = newmm;
424}
425
426void Translator::stripIdenticalSourceTranslations()
427{
428 TMM newmm;
429 for (TMM::ConstIterator it = m_messages.begin(); it != m_messages.end(); ++it) {
430 // we need to have just one translation, and it be equal to the source
431 if (it->translations().count() != 1)
432 newmm.append(*it);
433 else if (it->translation() != it->sourceText())
434 newmm.append(*it);
435 }
436 m_messages = newmm;
437}
438
439void Translator::dropTranslations()
440{
441 for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ++it) {
442 if (it->type() == TranslatorMessage::Finished)
443 it->setType(TranslatorMessage::Unfinished);
444 it->setTranslation(QString());
445 }
446}
447
448void Translator::dropUiLines()
449{
450 QString uiXt = QLatin1String(".ui");
451 QString juiXt = QLatin1String(".jui");
452 for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ++it) {
453 QHash<QString, int> have;
454 QList<TranslatorMessage::Reference> refs;
455 foreach (const TranslatorMessage::Reference &itref, it->allReferences()) {
456 const QString &fn = itref.fileName();
457 if (fn.endsWith(uiXt) || fn.endsWith(juiXt)) {
458 if (++have[fn] == 1)
459 refs.append(TranslatorMessage::Reference(fn, -1));
460 } else {
461 refs.append(itref);
462 }
463 }
464 it->setReferences(refs);
465 }
466}
467
468struct TranslatorMessageIdPtr {
469 explicit TranslatorMessageIdPtr(const TranslatorMessage &tm)
470 {
471 ptr = &tm;
472 }
473
474 inline const TranslatorMessage *operator->() const
475 {
476 return ptr;
477 }
478
479 const TranslatorMessage *ptr;
480};
481
482Q_DECLARE_TYPEINFO(TranslatorMessageIdPtr, Q_MOVABLE_TYPE);
483
484inline int qHash(TranslatorMessageIdPtr tmp)
485{
486 return qHash(tmp->id());
487}
488
489inline bool operator==(TranslatorMessageIdPtr tmp1, TranslatorMessageIdPtr tmp2)
490{
491 return tmp1->id() == tmp2->id();
492}
493
494struct TranslatorMessageContentPtr {
495 explicit TranslatorMessageContentPtr(const TranslatorMessage &tm)
496 {
497 ptr = &tm;
498 }
499
500 inline const TranslatorMessage *operator->() const
501 {
502 return ptr;
503 }
504
505 const TranslatorMessage *ptr;
506};
507
508Q_DECLARE_TYPEINFO(TranslatorMessageContentPtr, Q_MOVABLE_TYPE);
509
510inline int qHash(TranslatorMessageContentPtr tmp)
511{
512 int hash = qHash(tmp->context()) ^ qHash(tmp->sourceText());
513 if (!tmp->sourceText().isEmpty())
514 // Special treatment for context comments (empty source).
515 hash ^= qHash(tmp->comment());
516 return hash;
517}
518
519inline bool operator==(TranslatorMessageContentPtr tmp1, TranslatorMessageContentPtr tmp2)
520{
521 if (tmp1->context() != tmp2->context() || tmp1->sourceText() != tmp2->sourceText())
522 return false;
523 // Special treatment for context comments (empty source).
524 if (tmp1->sourceText().isEmpty())
525 return true;
526 return tmp1->comment() == tmp2->comment();
527}
528
529Translator::Duplicates Translator::resolveDuplicates()
530{
531 Duplicates dups;
532 QHash<TranslatorMessageIdPtr, int> idRefs;
533 QHash<TranslatorMessageContentPtr, int> contentRefs;
534 for (int i = 0; i < m_messages.count();) {
535 const TranslatorMessage &msg = m_messages.at(i);
536 TranslatorMessage *omsg;
537 int oi;
538 QSet<int> *pDup;
539 if (!msg.id().isEmpty()) {
540 QHash<TranslatorMessageIdPtr, int>::ConstIterator it =
541 idRefs.constFind(TranslatorMessageIdPtr(msg));
542 if (it != idRefs.constEnd()) {
543 oi = *it;
544 omsg = &m_messages[oi];
545 pDup = &dups.byId;
546 goto gotDupe;
547 }
548 }
549 {
550 QHash<TranslatorMessageContentPtr, int>::ConstIterator it =
551 contentRefs.constFind(TranslatorMessageContentPtr(msg));
552 if (it != contentRefs.constEnd()) {
553 oi = *it;
554 omsg = &m_messages[oi];
555 if (msg.id().isEmpty() || omsg->id().isEmpty()) {
556 if (!msg.id().isEmpty() && omsg->id().isEmpty()) {
557 omsg->setId(msg.id());
558 idRefs[TranslatorMessageIdPtr(*omsg)] = oi;
559 }
560 pDup = &dups.byContents;
561 goto gotDupe;
562 }
563 // This is really a content dupe, but with two distinct IDs.
564 }
565 }
566 if (!msg.id().isEmpty())
567 idRefs[TranslatorMessageIdPtr(msg)] = i;
568 contentRefs[TranslatorMessageContentPtr(msg)] = i;
569 ++i;
570 continue;
571 gotDupe:
572 if (omsg->isUtf8() != msg.isUtf8() && !omsg->isNonUtf8()) {
573 // Dual-encoded message
574 omsg->setUtf8(true);
575 omsg->setNonUtf8(true);
576 } else {
577 // Duplicate
578 pDup->insert(oi);
579 }
580 if (!omsg->isTranslated() && msg.isTranslated())
581 omsg->setTranslations(msg.translations());
582 m_messages.removeAt(i);
583 }
584 return dups;
585}
586
587void Translator::reportDuplicates(const Duplicates &dupes,
588 const QString &fileName, bool verbose)
589{
590 if (!dupes.byId.isEmpty() || !dupes.byContents.isEmpty()) {
591 std::cerr << "Warning: dropping duplicate messages in '" << qPrintable(fileName);
592 if (!verbose) {
593 std::cerr << "'\n(try -verbose for more info).\n";
594 } else {
595 std::cerr << "':\n";
596 foreach (int i, dupes.byId)
597 std::cerr << "\n* ID: " << qPrintable(message(i).id()) << std::endl;
598 foreach (int j, dupes.byContents) {
599 const TranslatorMessage &msg = message(j);
600 std::cerr << "\n* Context: " << qPrintable(msg.context())
601 << "\n* Source: " << qPrintable(msg.sourceText()) << std::endl;
602 if (!msg.comment().isEmpty())
603 std::cerr << "* Comment: " << qPrintable(msg.comment()) << std::endl;
604 }
605 std::cerr << std::endl;
606 }
607 }
608}
609
610// Used by lupdate to be able to search using absolute paths during merging
611void Translator::makeFileNamesAbsolute(const QDir &originalPath)
612{
613 TMM newmm;
614 for (TMM::iterator it = m_messages.begin(); it != m_messages.end(); ++it) {
615 TranslatorMessage msg = *it;
616 msg.setReferences(TranslatorMessage::References());
617 foreach (const TranslatorMessage::Reference &ref, it->allReferences()) {
618 QString fileName = ref.fileName();
619 QFileInfo fi (fileName);
620 if (fi.isRelative())
621 fileName = originalPath.absoluteFilePath(fileName);
622 msg.addReference(fileName, ref.lineNumber());
623 }
624 newmm.append(msg);
625 }
626 m_messages = newmm;
627}
628
629QList<TranslatorMessage> Translator::messages() const
630{
631 return m_messages;
632}
633
634QList<TranslatorMessage> Translator::translatedMessages() const
635{
636 TMM result;
637 for (TMM::ConstIterator it = m_messages.begin(); it != m_messages.end(); ++it)
638 if (it->type() == TranslatorMessage::Finished)
639 result.append(*it);
640 return result;
641}
642
643QStringList Translator::normalizedTranslations(const TranslatorMessage &msg, int numPlurals)
644{
645 QStringList translations = msg.translations();
646 int numTranslations = msg.isPlural() ? numPlurals : 1;
647
648 // make sure that the stringlist always have the size of the
649 // language's current numerus, or 1 if its not plural
650 if (translations.count() > numTranslations) {
651 for (int i = translations.count(); i > numTranslations; --i)
652 translations.removeLast();
653 } else if (translations.count() < numTranslations) {
654 for (int i = translations.count(); i < numTranslations; ++i)
655 translations.append(QString());
656 }
657 return translations;
658}
659
660void Translator::normalizeTranslations(ConversionData &cd)
661{
662 bool truncated = false;
663 QLocale::Language l;
664 QLocale::Country c;
665 languageAndCountry(languageCode(), &l, &c);
666 int numPlurals = 1;
667 if (l != QLocale::C) {
668 QStringList forms;
669 if (getNumerusInfo(l, c, 0, &forms, 0))
670 numPlurals = forms.count(); // includes singular
671 }
672 for (int i = 0; i < m_messages.count(); ++i) {
673 const TranslatorMessage &msg = m_messages.at(i);
674 QStringList tlns = msg.translations();
675 int ccnt = msg.isPlural() ? numPlurals : 1;
676 if (tlns.count() != ccnt) {
677 while (tlns.count() < ccnt)
678 tlns.append(QString());
679 while (tlns.count() > ccnt) {
680 tlns.removeLast();
681 truncated = true;
682 }
683 TranslatorMessage msg2(msg);
684 msg2.setTranslations(tlns);
685 m_messages[i] = msg2;
686 }
687 }
688 if (truncated)
689 cd.appendError(QLatin1String(
690 "Removed plural forms as the target language has less "
691 "forms.\nIf this sounds wrong, possibly the target language is "
692 "not set or recognized."));
693}
694
695QString Translator::guessLanguageCodeFromFileName(const QString &filename)
696{
697 QString str = filename;
698 foreach (const FileFormat &format, registeredFileFormats()) {
699 if (str.endsWith(format.extension)) {
700 str = str.left(str.size() - format.extension.size() - 1);
701 break;
702 }
703 }
704 static QRegExp re(QLatin1String("[\\._]"));
705 while (true) {
706 QLocale locale(str);
707 //qDebug() << "LANGUAGE FROM " << str << "LANG: " << locale.language();
708 if (locale.language() != QLocale::C) {
709 //qDebug() << "FOUND " << locale.name();
710 return locale.name();
711 }
712 int pos = str.indexOf(re);
713 if (pos == -1)
714 break;
715 str = str.mid(pos + 1);
716 }
717 //qDebug() << "LANGUAGE GUESSING UNSUCCESSFUL";
718 return QString();
719}
720
721bool Translator::hasExtra(const QString &key) const
722{
723 return m_extra.contains(key);
724}
725
726QString Translator::extra(const QString &key) const
727{
728 return m_extra[key];
729}
730
731void Translator::setExtra(const QString &key, const QString &value)
732{
733 m_extra[key] = value;
734}
735
736void Translator::setCodecName(const QByteArray &name)
737{
738 QTextCodec *codec = QTextCodec::codecForName(name);
739 if (!codec) {
740 if (!name.isEmpty())
741 std::cerr << "No QTextCodec for " << name.constData() << " available. Using Latin1.\n";
742 m_codec = QTextCodec::codecForName("ISO-8859-1");
743 } else {
744 m_codec = codec;
745 }
746}
747
748QByteArray Translator::codecName() const
749{
750 return m_codec->name();
751}
752
753void Translator::dump() const
754{
755 for (int i = 0; i != messageCount(); ++i)
756 message(i).dump();
757}
758
759QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.