Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

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

Location:
trunk
Files:
20 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/tools/linguist/shared/abstractproitemvisitor.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/numerus.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6565    { Q_EQ, 1, Q_NEWRULE,
    6666      Q_EQ, 2 };
    67 static const uchar slovakRules[] =
     67static const uchar slovakStyleRules[] =
    6868    { Q_EQ, 1, Q_NEWRULE,
    6969      Q_BETWEEN, 2, 4 };
     
    101101      Q_EQ, 2, Q_NEWRULE,
    102102      Q_MOD_100 | Q_BETWEEN, 3, 10, Q_NEWRULE,
    103       Q_MOD_100 | Q_NOT | Q_BETWEEN, 0, 2 };
     103      Q_MOD_100 | Q_GEQ, 11 };
    104104static const uchar tagalogRules[] =
    105105    { Q_LEQ, 1, Q_NEWRULE,
     
    115115static const char * const latvianForms[] = { "Singular", "Plural", "Nullar", 0 };
    116116static const char * const irishStyleForms[] = { "Singular", "Dual", "Plural", 0 };
    117 static const char * const slovakForms[] = { "Singular", "Paucal", "Plural", 0 };
     117static const char * const slovakStyleForms[] = { "Singular", "Paucal", "Plural", 0 };
    118118static const char * const macedonianForms[] = { "Singular", "Dual", "Plural", 0 };
    119119static const char * const lithuanianForms[] = { "Singular", "Paucal", "Plural", 0 };
     
    280280    EOL
    281281};
    282 static const QLocale::Language slovakLanguages[] = { QLocale::Slovak, QLocale::Czech, EOL };
     282static const QLocale::Language slovakStyleLanguages[] = { QLocale::Slovak, QLocale::Czech, EOL };
    283283static const QLocale::Language macedonianLanguage[] = { QLocale::Macedonian, EOL };
    284284static const QLocale::Language lithuanianLanguage[] = { QLocale::Lithuanian, EOL };
     
    319319    const QLocale::Language *languages;
    320320    const QLocale::Country *countries;
     321    const char * const gettextRules;
    321322};
    322323
    323324static const NumerusTableEntry numerusTable[] = {
    324     { 0, 0, japaneseStyleForms, japaneseStyleLanguages, 0 },
    325     { englishStyleRules, sizeof(englishStyleRules), englishStyleForms, englishStyleLanguages, 0 },
     325    { 0, 0, japaneseStyleForms, japaneseStyleLanguages, 0, "nplurals=1; plural=0;" },
     326    { englishStyleRules, sizeof(englishStyleRules), englishStyleForms, englishStyleLanguages, 0,
     327      "nplurals=2; plural=(n != 1);" },
    326328    { frenchStyleRules, sizeof(frenchStyleRules), frenchStyleForms, frenchStyleLanguages,
    327       frenchStyleCountries },
    328     { latvianRules, sizeof(latvianRules), latvianForms, latvianLanguage, 0 },
    329     { icelandicRules, sizeof(icelandicRules), icelandicForms, icelandicLanguage, 0 },
    330     { irishStyleRules, sizeof(irishStyleRules), irishStyleForms, irishStyleLanguages, 0 },
    331     { slovakRules, sizeof(slovakRules), slovakForms, slovakLanguages, 0 },
    332     { macedonianRules, sizeof(macedonianRules), macedonianForms, macedonianLanguage, 0 },
    333     { lithuanianRules, sizeof(lithuanianRules), lithuanianForms, lithuanianLanguage, 0 },
    334     { russianStyleRules, sizeof(russianStyleRules), russianStyleForms, russianStyleLanguages, 0 },
    335     { polishRules, sizeof(polishRules), polishForms, polishLanguage, 0 },
    336     { romanianRules, sizeof(romanianRules), romanianForms, romanianLanguages, 0 },
    337     { slovenianRules, sizeof(slovenianRules), slovenianForms, slovenianLanguage, 0 },
    338     { malteseRules, sizeof(malteseRules), malteseForms, malteseLanguage, 0 },
    339     { welshRules, sizeof(welshRules), welshForms, welshLanguage, 0 },
    340     { arabicRules, sizeof(arabicRules), arabicForms, arabicLanguage, 0 },
    341     { tagalogRules, sizeof(tagalogRules), tagalogForms, tagalogLanguage, 0 },
    342     { catalanRules, sizeof(catalanRules), catalanForms, catalanLanguage, 0 }
     329      frenchStyleCountries, "nplurals=2; plural=(n > 1);" },
     330    { latvianRules, sizeof(latvianRules), latvianForms, latvianLanguage, 0,
     331      "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);" },
     332    { icelandicRules, sizeof(icelandicRules), icelandicForms, icelandicLanguage, 0,
     333      "nplurals=2; plural=(n%10==1 && n%100!=11 ? 0 : 1);" },
     334    { irishStyleRules, sizeof(irishStyleRules), irishStyleForms, irishStyleLanguages, 0,
     335      "nplurals=3; plural=(n==1 ? 0 : n==2 ? 1 : 2);" },
     336    { slovakStyleRules, sizeof(slovakStyleRules), slovakStyleForms, slovakStyleLanguages, 0,
     337      "nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);" },
     338    { macedonianRules, sizeof(macedonianRules), macedonianForms, macedonianLanguage, 0,
     339      "nplurals=3; plural=(n%100==1 ? 0 : n%100==2 ? 1 : 2);" },
     340    { lithuanianRules, sizeof(lithuanianRules), lithuanianForms, lithuanianLanguage, 0,
     341      "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);" },
     342    { russianStyleRules, sizeof(russianStyleRules), russianStyleForms, russianStyleLanguages, 0,
     343      "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" },
     344    { polishRules, sizeof(polishRules), polishForms, polishLanguage, 0,
     345      "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" },
     346    { romanianRules, sizeof(romanianRules), romanianForms, romanianLanguages, 0,
     347      "nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2);" },
     348    { slovenianRules, sizeof(slovenianRules), slovenianForms, slovenianLanguage, 0,
     349      "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);" },
     350    { malteseRules, sizeof(malteseRules), malteseForms, malteseLanguage, 0,
     351      "nplurals=4; plural=(n==1 ? 0 : (n==0 || (n%100>=1 && n%100<=10)) ? 1 : (n%100>=11 && n%100<=19) ? 2 : 3);" },
     352    { welshRules, sizeof(welshRules), welshForms, welshLanguage, 0,
     353      "nplurals=5; plural=(n==0 ? 0 : n==1 ? 1 : (n>=2 && n<=5) ? 2 : n==6 ? 3 : 4);" },
     354    { arabicRules, sizeof(arabicRules), arabicForms, arabicLanguage, 0,
     355      "nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : (n%100>=3 && n%100<=10) ? 3 : n%100>=11 ? 4 : 5);" },
     356    { tagalogRules, sizeof(tagalogRules), tagalogForms, tagalogLanguage, 0,
     357      "nplurals=3; plural=(n==1 ? 0 : (n%10==4 || n%10==6 || n%10== 9) ? 1 : 2);" },
     358    { catalanRules, sizeof(catalanRules), catalanForms, catalanLanguage, 0,
     359      "nplurals=3; plural=(n==1 ? 0 : (n==11 || n/1000==11 || n/1000000==11 || n/1000000000==11) ? 1 : 2);" },
    343360};
    344361
     
    353370
    354371bool getNumerusInfo(QLocale::Language language, QLocale::Country country,
    355                            QByteArray *rules, QStringList *forms)
     372                    QByteArray *rules, QStringList *forms, const char **gettextRules)
    356373{
    357374    while (true) {
     
    366383                                                    entry.rulesSize);
    367384                    }
     385                    if (gettextRules)
     386                        *gettextRules = entry.gettextRules;
    368387                    if (forms) {
    369388                        forms->clear();
  • trunk/tools/linguist/shared/po.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4646#include <QtCore/QHash>
    4747#include <QtCore/QString>
     48#include <QtCore/QTextCodec>
    4849#include <QtCore/QTextStream>
    4950
    5051#include <ctype.h>
    51 
    52 #define MAGIC_OBSOLETE_REFERENCE "Obsolete_PO_entries"
    5352
    5453// Uncomment if you wish to hard wrap long lines in .po files. Note that this
     
    202201
    203202public:
    204     QString id;
    205     QString context;
    206     QString tscomment;
    207     QString oldTscomment;
    208     QString lineNumber;
    209     QString fileName;
    210     QString references;
    211     QString translatorComments;
    212     QString automaticComments;
    213     QString msgId;
    214     QString oldMsgId;
    215     QStringList msgStr;
     203    QByteArray id;
     204    QByteArray context;
     205    QByteArray tscomment;
     206    QByteArray oldTscomment;
     207    QByteArray lineNumber;
     208    QByteArray fileName;
     209    QByteArray references;
     210    QByteArray translatorComments;
     211    QByteArray automaticComments;
     212    QByteArray msgId;
     213    QByteArray oldMsgId;
     214    QList<QByteArray> msgStr;
    216215    bool isPlural;
    217216    bool isFuzzy;
     
    220219
    221220
    222 static bool isTranslationLine(const QString &line)
    223 {
    224     return line.startsWith(QLatin1String("#~ msgstr"))
    225            || line.startsWith(QLatin1String("msgstr"));
    226 }
    227 
    228 static QString slurpEscapedString(const QStringList &lines, int & l,
    229         int offset, const QString &prefix, ConversionData &cd)
    230 {
    231     QString msg;
     221static bool isTranslationLine(const QByteArray &line)
     222{
     223    return line.startsWith("#~ msgstr") || line.startsWith("msgstr");
     224}
     225
     226static QByteArray slurpEscapedString(const QList<QByteArray> &lines, int &l,
     227        int offset, const QByteArray &prefix, ConversionData &cd)
     228{
     229    QByteArray msg;
    232230    int stoff;
    233231
    234232    for (; l < lines.size(); ++l) {
    235         const QString &line = lines.at(l);
     233        const QByteArray &line = lines.at(l);
    236234        if (line.isEmpty() || !line.startsWith(prefix))
    237235            break;
    238         while (line[offset].isSpace()) // No length check, as string has no trailing spaces.
     236        while (isspace(line[offset])) // No length check, as string has no trailing spaces.
    239237            offset++;
    240         if (line[offset].unicode() != '"')
     238        if (line[offset] != '"')
    241239            break;
    242240        offset++;
     
    244242            if (offset == line.length())
    245243                goto premature_eol;
    246             ushort c = line[offset++].unicode();
     244            uchar c = line[offset++];
    247245            if (c == '"') {
    248246                if (offset == line.length())
    249247                    break;
    250                 while (line[offset].isSpace())
     248                while (isspace(line[offset]))
    251249                    offset++;
    252                 if (line[offset++].unicode() != '"') {
     250                if (line[offset++] != '"') {
    253251                    cd.appendError(QString::fromLatin1(
    254252                            "PO parsing error: extra characters on line %1.")
     
    261259                if (offset == line.length())
    262260                    goto premature_eol;
    263                 c = line[offset++].unicode();
     261                c = line[offset++];
    264262                switch (c) {
    265263                case 'r':
    266                     msg += QLatin1Char('\r'); // Maybe just throw it away?
     264                    msg += '\r'; // Maybe just throw it away?
    267265                    break;
    268266                case 'n':
    269                     msg += QLatin1Char('\n');
     267                    msg += '\n';
    270268                    break;
    271269                case 't':
    272                     msg += QLatin1Char('\t');
     270                    msg += '\t';
    273271                    break;
    274272                case 'v':
    275                     msg += QLatin1Char('\v');
     273                    msg += '\v';
    276274                    break;
    277275                case 'a':
    278                     msg += QLatin1Char('\a');
     276                    msg += '\a';
    279277                    break;
    280278                case 'b':
    281                     msg += QLatin1Char('\b');
     279                    msg += '\b';
    282280                    break;
    283281                case 'f':
    284                     msg += QLatin1Char('\f');
     282                    msg += '\f';
    285283                    break;
    286284                case '"':
    287                     msg += QLatin1Char('"');
     285                    msg += '"';
    288286                    break;
    289287                case '\\':
    290                     msg += QLatin1Char('\\');
     288                    msg += '\\';
    291289                    break;
    292290                case '0':
     
    299297                case '7':
    300298                    stoff = offset - 1;
    301                     while ((c = line[offset].unicode()) >= '0' && c <= '7')
     299                    while ((c = line[offset]) >= '0' && c <= '7')
    302300                        if (++offset == line.length())
    303301                            goto premature_eol;
    304                     msg += QChar(line.mid(stoff, offset - stoff).toUInt(0, 8));
     302                    msg += line.mid(stoff, offset - stoff).toUInt(0, 8);
    305303                    break;
    306304                case 'x':
    307305                    stoff = offset;
    308                     while (isxdigit(line[offset].unicode()))
     306                    while (isxdigit(line[offset]))
    309307                        if (++offset == line.length())
    310308                            goto premature_eol;
    311                     msg += QChar(line.mid(stoff, offset - stoff).toUInt(0, 16));
     309                    msg += line.mid(stoff, offset - stoff).toUInt(0, 16);
    312310                    break;
    313311                default:
    314312                    cd.appendError(QString::fromLatin1(
    315313                            "PO parsing error: invalid escape '\\%1' (line %2).")
    316                             .arg(QChar(c)).arg(l + 1));
    317                     msg += QLatin1Char('\\');
    318                     msg += QChar(c);
     314                            .arg(QChar((uint)c)).arg(l + 1));
     315                    msg += '\\';
     316                    msg += c;
    319317                    break;
    320318                }
    321319            } else {
    322                 msg += QChar(c);
     320                msg += c;
    323321            }
    324322        }
     
    331329    cd.appendError(QString::fromLatin1(
    332330            "PO parsing error: premature end of line %1.").arg(l + 1));
    333     return QString();
    334 }
    335 
    336 static void slurpComment(QString &msg, const QStringList &lines, int & l)
    337 {
    338     const QChar newline = QLatin1Char('\n');
    339     QString prefix = lines.at(l);
     331    return QByteArray();
     332}
     333
     334static void slurpComment(QByteArray &msg, const QList<QByteArray> &lines, int & l)
     335{
     336    QByteArray prefix = lines.at(l);
    340337    for (int i = 1; ; i++) {
    341         if (prefix.at(i).unicode() != ' ') {
     338        if (prefix.at(i) != ' ') {
    342339            prefix.truncate(i);
    343340            break;
     
    345342    }
    346343    for (; l < lines.size(); ++l) {
    347         const QString &line = lines.at(l);
     344        const QByteArray &line = lines.at(l);
    348345        if (line.startsWith(prefix))
    349346            msg += line.mid(prefix.size());
    350         else if (line != QLatin1String("#"))
    351             break;
    352         msg += newline;
     347        else if (line != "#")
     348            break;
     349        msg += '\n';
    353350    }
    354351    --l;
    355352}
    356353
     354static void splitContext(QByteArray *comment, QByteArray *context)
     355{
     356    char *data = comment->data();
     357    int len = comment->size();
     358    int sep = -1, j = 0;
     359
     360    for (int i = 0; i < len; i++, j++) {
     361        if (data[i] == '~' && i + 1 < len)
     362            i++;
     363        else if (data[i] == '|')
     364            sep = j;
     365        data[j] = data[i];
     366    }
     367    if (sep >= 0) {
     368        QByteArray tmp = comment->mid(sep + 1, j - sep - 1);
     369        comment->truncate(sep);
     370        *context = *comment;
     371        *comment = tmp;
     372    } else {
     373        comment->truncate(j);
     374    }
     375}
     376
     377static QString makePoHeader(const QString &str)
     378{
     379    return QLatin1String("po-header-") + str.toLower().replace(QLatin1Char('-'), QLatin1Char('_'));
     380}
     381
     382static QByteArray QByteArrayList_join(const QList<QByteArray> &that, char sep)
     383{
     384    int totalLength = 0;
     385    const int size = that.size();
     386
     387    for (int i = 0; i < size; ++i)
     388        totalLength += that.at(i).size();
     389
     390    if (size > 0)
     391        totalLength += size - 1;
     392
     393    QByteArray res;
     394    if (totalLength == 0)
     395        return res;
     396    res.reserve(totalLength);
     397    for (int i = 0; i < that.size(); ++i) {
     398        if (i)
     399            res += sep;
     400        res += that.at(i);
     401    }
     402    return res;
     403}
     404
    357405bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd)
    358406{
    359     const QChar quote = QLatin1Char('"');
    360     const QChar newline = QLatin1Char('\n');
    361     QTextStream in(&dev);
    362     in.setCodec(cd.m_codecForSource.isEmpty() ? QByteArray("UTF-8") : cd.m_codecForSource);
     407    QTextCodec *codec = QTextCodec::codecForName(
     408            cd.m_codecForSource.isEmpty() ? QByteArray("UTF-8") : cd.m_codecForSource);
    363409    bool error = false;
    364410
     
    381427
    382428    // we need line based lookahead below.
    383     QStringList lines;
    384     while (!in.atEnd())
    385         lines.append(in.readLine().trimmed());
    386     lines.append(QString());
    387 
    388     int l = 0;
     429    QList<QByteArray> lines;
     430    while (!dev.atEnd())
     431        lines.append(dev.readLine().trimmed());
     432    lines.append(QByteArray());
     433
     434    int l = 0, lastCmtLine = -1;
     435    bool qtContexts = false;
    389436    PoItem item;
    390437    for (; l != lines.size(); ++l) {
    391         QString line = lines.at(l);
     438        QByteArray line = lines.at(l);
    392439        if (line.isEmpty())
    393440           continue;
    394441        if (isTranslationLine(line)) {
    395             bool isObsolete = line.startsWith(QLatin1String("#~ msgstr"));
    396             const QString prefix = QLatin1String(isObsolete ? "#~ " : "");
     442            bool isObsolete = line.startsWith("#~ msgstr");
     443            const QByteArray prefix = isObsolete ? "#~ " : "";
    397444            while (true) {
    398                 int idx = line.indexOf(QLatin1Char(' '), prefix.length());
    399                 QString str = slurpEscapedString(lines, l, idx, prefix, cd);
     445                int idx = line.indexOf(' ', prefix.length());
     446                QByteArray str = slurpEscapedString(lines, l, idx, prefix, cd);
     447                item.msgStr.append(str);
     448                if (l + 1 >= lines.size() || !isTranslationLine(lines.at(l + 1)))
     449                    break;
     450                ++l;
     451                line = lines.at(l);
     452            }
     453            if (item.msgId.isEmpty()) {
     454                QHash<QString, QByteArray> extras;
     455                QList<QByteArray> hdrOrder;
     456                QByteArray pluralForms;
     457                foreach (const QByteArray &hdr, item.msgStr.first().split('\n')) {
     458                    if (hdr.isEmpty())
     459                        continue;
     460                    int idx = hdr.indexOf(':');
     461                    if (idx < 0) {
     462                        cd.appendError(QString::fromLatin1("Unexpected PO header format '%1'")
     463                            .arg(QString::fromLatin1(hdr)));
     464                        error = true;
     465                        break;
     466                    }
     467                    QByteArray hdrName = hdr.left(idx).trimmed();
     468                    QByteArray hdrValue = hdr.mid(idx + 1).trimmed();
     469                    hdrOrder << hdrName;
     470                    if (hdrName == "X-Language") {
     471                        translator.setLanguageCode(QString::fromLatin1(hdrValue));
     472                    } else if (hdrName == "X-Source-Language") {
     473                        translator.setSourceLanguageCode(QString::fromLatin1(hdrValue));
     474                    } else if (hdrName == "X-Qt-Contexts") {
     475                        qtContexts = (hdrValue == "true");
     476                    } else if (hdrName == "Plural-Forms") {
     477                        pluralForms  = hdrValue;
     478                    } else if (hdrName == "MIME-Version") {
     479                        // just assume it is 1.0
     480                    } else if (hdrName == "Content-Type") {
     481                        if (cd.m_codecForSource.isEmpty()) {
     482                            if (!hdrValue.startsWith("text/plain; charset=")) {
     483                                cd.appendError(QString::fromLatin1("Unexpected Content-Type header '%1'")
     484                                    .arg(QString::fromLatin1(hdrValue)));
     485                                error = true;
     486                                // This will avoid a flood of conversion errors.
     487                                codec = QTextCodec::codecForName("latin1");
     488                            } else {
     489                                QByteArray cod = hdrValue.mid(20);
     490                                QTextCodec *cdc = QTextCodec::codecForName(cod);
     491                                if (!cdc) {
     492                                    cd.appendError(QString::fromLatin1("Unsupported codec '%1'")
     493                                            .arg(QString::fromLatin1(cod)));
     494                                    error = true;
     495                                    // This will avoid a flood of conversion errors.
     496                                    codec = QTextCodec::codecForName("latin1");
     497                                } else {
     498                                    codec = cdc;
     499                                }
     500                            }
     501                        }
     502                    } else if (hdrName == "Content-Transfer-Encoding") {
     503                        if (hdrValue != "8bit") {
     504                            cd.appendError(QString::fromLatin1("Unexpected Content-Transfer-Encoding '%1'")
     505                                .arg(QString::fromLatin1(hdrValue)));
     506                            return false;
     507                        }
     508                    } else if (hdrName == "X-Virgin-Header") {
     509                        // legacy
     510                    } else {
     511                        extras[makePoHeader(QString::fromLatin1(hdrName))] = hdrValue;
     512                    }
     513                }
     514                if (!pluralForms.isEmpty()) {
     515                    if (translator.languageCode().isEmpty()) {
     516                        extras[makePoHeader(QLatin1String("Plural-Forms"))] = pluralForms;
     517                    } else {
     518                         // FIXME: have fun with making a consistency check ...
     519                    }
     520                }
     521                // Eliminate the field if only headers we added are present in standard order.
     522                // Keep in sync with savePO
     523                static const char * const dfltHdrs[] = {
     524                    "MIME-Version", "Content-Type", "Content-Transfer-Encoding",
     525                    "Plural-Forms", "X-Language", "X-Source-Language", "X-Qt-Contexts"
     526                };
     527                uint cdh = 0;
     528                for (int cho = 0; cho < hdrOrder.length(); cho++) {
     529                    for (;; cdh++) {
     530                        if (cdh == sizeof(dfltHdrs)/sizeof(dfltHdrs[0])) {
     531                            extras[QLatin1String("po-headers")] =
     532                                    QByteArrayList_join(hdrOrder, ',');
     533                            goto doneho;
     534                        }
     535                        if (hdrOrder.at(cho) == dfltHdrs[cdh]) {
     536                            cdh++;
     537                            break;
     538                        }
     539                    }
     540                }
     541              doneho:
     542                if (lastCmtLine != -1)
     543                    extras[QLatin1String("po-header_comment")] =
     544                            QByteArrayList_join(lines.mid(0, lastCmtLine + 1), '\n');
     545                for (QHash<QString, QByteArray>::ConstIterator it = extras.constBegin(),
     546                                                               end = extras.constEnd();
     547                     it != end; ++it)
     548                    translator.setExtra(it.key(), codec->toUnicode(it.value()));
     549                item = PoItem();
     550                continue;
     551            }
     552            // build translator message
     553            TranslatorMessage msg;
     554            msg.setContext(codec->toUnicode(item.context));
     555            if (!item.references.isEmpty()) {
     556                QString xrefs;
     557                foreach (const QString &ref,
     558                         codec->toUnicode(item.references).split(
     559                                 QRegExp(QLatin1String("\\s")), QString::SkipEmptyParts)) {
     560                    int pos = ref.indexOf(QLatin1Char(':'));
     561                    int lpos = ref.lastIndexOf(QLatin1Char(':'));
     562                    if (pos != -1 && pos == lpos) {
     563                        bool ok;
     564                        int lno = ref.mid(pos + 1).toInt(&ok);
     565                        if (ok) {
     566                            msg.addReference(ref.left(pos), lno);
     567                            continue;
     568                        }
     569                    }
     570                    if (!xrefs.isEmpty())
     571                        xrefs += QLatin1Char(' ');
     572                    xrefs += ref;
     573                }
     574                if (!xrefs.isEmpty())
     575                    item.extra[QLatin1String("po-references")] = xrefs;
     576            }
     577            msg.setId(codec->toUnicode(item.id));
     578            msg.setSourceText(codec->toUnicode(item.msgId));
     579            msg.setOldSourceText(codec->toUnicode(item.oldMsgId));
     580            msg.setComment(codec->toUnicode(item.tscomment));
     581            msg.setOldComment(codec->toUnicode(item.oldTscomment));
     582            msg.setExtraComment(codec->toUnicode(item.automaticComments));
     583            msg.setTranslatorComment(codec->toUnicode(item.translatorComments));
     584            msg.setPlural(item.isPlural || item.msgStr.size() > 1);
     585            QStringList translations;
     586            foreach (const QByteArray &bstr, item.msgStr) {
     587                QString str = codec->toUnicode(bstr);
    400588                str.replace(QChar(Translator::TextVariantSeparator),
    401589                            QChar(Translator::BinaryVariantSeparator));
    402                 item.msgStr.append(str);
    403                 if (l + 1 >= lines.size() || !isTranslationLine(lines.at(l + 1)))
    404                     break;
    405                 ++l;
    406                 line = lines.at(l);
    407             }
    408             if (item.msgId.isEmpty()) {
    409                 QRegExp rx(QLatin1String("\\bX-Language: ([^\n]*)\n"));
    410                 int idx = rx.indexIn(item.msgStr.first());
    411                 if (idx >= 0) {
    412                     translator.setLanguageCode(rx.cap(1));
    413                     item.msgStr.first().remove(idx, rx.matchedLength());
    414                 }
    415                 QRegExp rx2(QLatin1String("\\bX-Source-Language: ([^\n]*)\n"));
    416                 int idx2 = rx2.indexIn(item.msgStr.first());
    417                 if (idx2 >= 0) {
    418                     translator.setSourceLanguageCode(rx2.cap(1));
    419                     item.msgStr.first().remove(idx2, rx2.matchedLength());
    420                 }
    421                 if (item.msgStr.first().indexOf(
    422                         QRegExp(QLatin1String("\\bX-Virgin-Header:[^\n]*\n"))) >= 0) {
    423                     item = PoItem();
    424                     continue;
    425                 }
    426             }
    427             // build translator message
    428             TranslatorMessage msg;
    429             msg.setContext(item.context);
    430             if (!item.references.isEmpty()) {
    431                 foreach (const QString &ref,
    432                          item.references.split(QRegExp(QLatin1String("\\s")),
    433                                                QString::SkipEmptyParts)) {
    434                     int pos = ref.lastIndexOf(QLatin1Char(':'));
    435                     if (pos != -1)
    436                         msg.addReference(ref.left(pos), ref.mid(pos + 1).toInt());
    437                 }
    438             } else if (isObsolete) {
    439                 msg.setFileName(QLatin1String(MAGIC_OBSOLETE_REFERENCE));
    440             }
    441             msg.setId(item.id);
    442             msg.setSourceText(item.msgId);
    443             msg.setOldSourceText(item.oldMsgId);
    444             msg.setComment(item.tscomment);
    445             msg.setOldComment(item.oldTscomment);
    446             msg.setExtraComment(item.automaticComments);
    447             msg.setTranslatorComment(item.translatorComments);
    448             msg.setPlural(item.isPlural || item.msgStr.size() > 1);
    449             msg.setTranslations(item.msgStr);
     590                translations << str;
     591            }
     592            msg.setTranslations(translations);
    450593            if (isObsolete)
    451594                msg.setType(TranslatorMessage::Obsolete);
    452             else if (item.isFuzzy)
     595            else if (item.isFuzzy || (!msg.sourceText().isEmpty() && !msg.isTranslated()))
    453596                msg.setType(TranslatorMessage::Unfinished);
    454597            else
     
    461604            translator.append(msg);
    462605            item = PoItem();
    463         } else if (line.startsWith(QLatin1Char('#'))) {
    464             switch(line.size() < 2 ? 0 : line.at(1).unicode()) {
     606        } else if (line.startsWith('#')) {
     607            switch (line.size() < 2 ? 0 : line.at(1)) {
    465608                case ':':
    466609                    item.references += line.mid(3);
    467                     item.references += newline;
     610                    item.references += '\n';
    468611                    break;
    469612                case ',': {
    470613                    QStringList flags =
    471                             line.mid(2).split(QRegExp(QLatin1String("[, ]")),
    472                                               QString::SkipEmptyParts);
     614                            QString::fromLatin1(line.mid(2)).split(
     615                                    QRegExp(QLatin1String("[, ]")), QString::SkipEmptyParts);
    473616                    if (flags.removeOne(QLatin1String("fuzzy")))
    474617                        item.isFuzzy = true;
     618                    flags.removeOne(QLatin1String("qt-format"));
    475619                    TranslatorMessage::ExtraData::const_iterator it =
    476620                            item.extra.find(QLatin1String("po-flags"));
     
    482626                }
    483627                case 0:
    484                     item.translatorComments += newline;
     628                    item.translatorComments += '\n';
    485629                    break;
    486630                case ' ':
     
    488632                    break;
    489633                case '.':
    490                     if (line.startsWith(QLatin1String("#. ts-context "))) {
     634                    if (line.startsWith("#. ts-context ")) { // legacy
    491635                        item.context = line.mid(14);
    492                     } else if (line.startsWith(QLatin1String("#. ts-id "))) {
     636                    } else if (line.startsWith("#. ts-id ")) {
    493637                        item.id = line.mid(9);
    494638                    } else {
    495639                        item.automaticComments += line.mid(3);
    496                         item.automaticComments += newline;
     640                        item.automaticComments += '\n';
    497641                    }
    498642                    break;
    499643                case '|':
    500                     if (line.startsWith(QLatin1String("#| msgid "))) {
    501                         item.oldMsgId = slurpEscapedString(lines, l, 9, QLatin1String("#| "), cd);
    502                     } else if (line.startsWith(QLatin1String("#| msgid_plural "))) {
    503                         QString extra = slurpEscapedString(lines, l, 16, QLatin1String("#| "), cd);
     644                    if (line.startsWith("#| msgid ")) {
     645                        item.oldMsgId = slurpEscapedString(lines, l, 9, "#| ", cd);
     646                    } else if (line.startsWith("#| msgid_plural ")) {
     647                        QByteArray extra = slurpEscapedString(lines, l, 16, "#| ", cd);
    504648                        if (extra != item.oldMsgId)
    505                             item.extra[QLatin1String("po-old_msgid_plural")] = extra;
    506                     } else if (line.startsWith(QLatin1String("#| msgctxt "))) {
    507                         item.oldTscomment = slurpEscapedString(lines, l, 11, QLatin1String("#| "), cd);
     649                            item.extra[QLatin1String("po-old_msgid_plural")] =
     650                                    codec->toUnicode(extra);
     651                    } else if (line.startsWith("#| msgctxt ")) {
     652                        item.oldTscomment = slurpEscapedString(lines, l, 11, "#| ", cd);
     653                        if (qtContexts)
     654                            splitContext(&item.oldTscomment, &item.context);
    508655                    } else {
    509                         cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'\n"))
    510                             .arg(l + 1).arg(lines[l]));
     656                        cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'"))
     657                            .arg(l + 1).arg(codec->toUnicode(lines[l])));
    511658                        error = true;
    512659                    }
    513660                    break;
    514661                case '~':
    515                     if (line.startsWith(QLatin1String("#~ msgid "))) {
    516                         item.msgId = slurpEscapedString(lines, l, 9, QLatin1String("#~ "), cd);
    517                     } else if (line.startsWith(QLatin1String("#~ msgid_plural "))) {
    518                         QString extra = slurpEscapedString(lines, l, 16, QLatin1String("#~ "), cd);
     662                    if (line.startsWith("#~ msgid ")) {
     663                        item.msgId = slurpEscapedString(lines, l, 9, "#~ ", cd);
     664                    } else if (line.startsWith("#~ msgid_plural ")) {
     665                        QByteArray extra = slurpEscapedString(lines, l, 16, "#~ ", cd);
    519666                        if (extra != item.msgId)
    520                             item.extra[QLatin1String("po-msgid_plural")] = extra;
     667                            item.extra[QLatin1String("po-msgid_plural")] =
     668                                    codec->toUnicode(extra);
    521669                        item.isPlural = true;
    522                     } else if (line.startsWith(QLatin1String("#~ msgctxt "))) {
    523                         item.tscomment = slurpEscapedString(lines, l, 11, QLatin1String("#~ "), cd);
     670                    } else if (line.startsWith("#~ msgctxt ")) {
     671                        item.tscomment = slurpEscapedString(lines, l, 11, "#~ ", cd);
     672                        if (qtContexts)
     673                            splitContext(&item.tscomment, &item.context);
    524674                    } else {
    525                         cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'\n"))
    526                             .arg(l + 1).arg(lines[l]));
     675                        cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'"))
     676                            .arg(l + 1).arg(codec->toUnicode(lines[l])));
    527677                        error = true;
    528678                    }
    529679                    break;
    530680                default:
    531                     cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'\n"))
    532                         .arg(l + 1).arg(lines[l]));
     681                    cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'"))
     682                        .arg(l + 1).arg(codec->toUnicode(lines[l])));
    533683                    error = true;
    534684                    break;
    535685            }
    536         } else if (line.startsWith(QLatin1String("msgctxt "))) {
    537             item.tscomment = slurpEscapedString(lines, l, 8, QString(), cd);
    538         } else if (line.startsWith(QLatin1String("msgid "))) {
    539             item.msgId = slurpEscapedString(lines, l, 6, QString(), cd);
    540         } else if (line.startsWith(QLatin1String("msgid_plural "))) {
    541             QString extra = slurpEscapedString(lines, l, 13, QString(), cd);
     686            lastCmtLine = l;
     687        } else if (line.startsWith("msgctxt ")) {
     688            item.tscomment = slurpEscapedString(lines, l, 8, QByteArray(), cd);
     689            if (qtContexts)
     690                splitContext(&item.tscomment, &item.context);
     691        } else if (line.startsWith("msgid ")) {
     692            item.msgId = slurpEscapedString(lines, l, 6, QByteArray(), cd);
     693        } else if (line.startsWith("msgid_plural ")) {
     694            QByteArray extra = slurpEscapedString(lines, l, 13, QByteArray(), cd);
    542695            if (extra != item.msgId)
    543                 item.extra[QLatin1String("po-msgid_plural")] = extra;
     696                item.extra[QLatin1String("po-msgid_plural")] = codec->toUnicode(extra);
    544697            item.isPlural = true;
    545698        } else {
    546             cd.appendError(QString(QLatin1String("PO-format error in line %1: '%2'\n"))
    547                 .arg(l + 1).arg(lines[l]));
     699            cd.appendError(QString(QLatin1String("PO-format error in line %1: '%2'"))
     700                .arg(l + 1).arg(codec->toUnicode(lines[l])));
    548701            error = true;
    549702        }
     
    552705}
    553706
     707static void addPoHeader(Translator::ExtraData &headers, QStringList &hdrOrder,
     708                        const char *name, const QString &value)
     709{
     710    QString qName = QLatin1String(name);
     711    if (!hdrOrder.contains(qName))
     712        hdrOrder << qName;
     713    headers[makePoHeader(qName)] = value;
     714}
     715
     716static QString escapeComment(const QString &in, bool escape)
     717{
     718    QString out = in;
     719    if (escape) {
     720        out.replace(QLatin1Char('~'), QLatin1String("~~"));
     721        out.replace(QLatin1Char('|'), QLatin1String("~|"));
     722    }
     723    return out;
     724}
     725
    554726bool savePO(const Translator &translator, QIODevice &dev, ConversionData &cd)
    555727{
     728    QString str_format = QLatin1String("-format");
     729
    556730    bool ok = true;
    557731    QTextStream out(&dev);
    558732    out.setCodec(cd.m_outputCodec.isEmpty() ? QByteArray("UTF-8") : cd.m_outputCodec);
    559733
    560     bool first = true;
    561     if (translator.messages().isEmpty() || !translator.messages().first().sourceText().isEmpty()) {
    562         out <<
    563             "# SOME DESCRIPTIVE TITLE.\n"
    564             "# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n"
    565             "# This file is distributed under the same license as the PACKAGE package.\n"
    566             "# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n"
    567             "#\n"
    568             "#, fuzzy\n"
    569             "msgid \"\"\n"
    570             "msgstr \"\"\n"
    571             "\"X-Virgin-Header: remove this line if you change anything in the header.\\n\"\n";
    572         if (!translator.languageCode().isEmpty())
    573             out << "\"X-Language: " << translator.languageCode() << "\\n\"\n";
    574         if (!translator.sourceLanguageCode().isEmpty())
    575             out << "\"X-Source-Language: " << translator.sourceLanguageCode() << "\\n\"\n";
    576         first = false;
    577     }
     734    bool qtContexts = false;
     735    foreach (const TranslatorMessage &msg, translator.messages())
     736        if (!msg.context().isEmpty()) {
     737            qtContexts = true;
     738            break;
     739        }
     740
     741    QString cmt = translator.extra(QLatin1String("po-header_comment"));
     742    if (!cmt.isEmpty())
     743        out << cmt << '\n';
     744    out << "msgid \"\"\n";
     745    Translator::ExtraData headers = translator.extras();
     746    QStringList hdrOrder = translator.extra(QLatin1String("po-headers")).split(
     747            QLatin1Char(','), QString::SkipEmptyParts);
     748    // Keep in sync with loadPO
     749    addPoHeader(headers, hdrOrder, "MIME-Version", QLatin1String("1.0"));
     750    addPoHeader(headers, hdrOrder, "Content-Type",
     751                QLatin1String("text/plain; charset=" + out.codec()->name()));
     752    addPoHeader(headers, hdrOrder, "Content-Transfer-Encoding", QLatin1String("8bit"));
     753    if (!translator.languageCode().isEmpty()) {
     754        QLocale::Language l;
     755        QLocale::Country c;
     756        Translator::languageAndCountry(translator.languageCode(), &l, &c);
     757        const char *gettextRules;
     758        if (getNumerusInfo(l, c, 0, 0, &gettextRules))
     759            addPoHeader(headers, hdrOrder, "Plural-Forms", QLatin1String(gettextRules));
     760        addPoHeader(headers, hdrOrder, "X-Language", translator.languageCode());
     761    }
     762    if (!translator.sourceLanguageCode().isEmpty())
     763        addPoHeader(headers, hdrOrder, "X-Source-Language", translator.sourceLanguageCode());
     764    if (qtContexts)
     765        addPoHeader(headers, hdrOrder, "X-Qt-Contexts", QLatin1String("true"));
     766    QString hdrStr;
     767    foreach (const QString &hdr, hdrOrder) {
     768        hdrStr += hdr;
     769        hdrStr += QLatin1String(": ");
     770        hdrStr += headers.value(makePoHeader(hdr));
     771        hdrStr += QLatin1Char('\n');
     772    }
     773    out << poEscapedString(QString(), QString::fromLatin1("msgstr"), true, hdrStr);
     774
    578775    foreach (const TranslatorMessage &msg, translator.messages()) {
    579         if (!first)
    580             out << endl;
     776        out << endl;
    581777
    582778        if (!msg.translatorComment().isEmpty())
     
    586782            out << poEscapedLines(QLatin1String("#."), true, msg.extraComment());
    587783
    588         if (!msg.context().isEmpty())
    589             out << QLatin1String("#. ts-context ") << msg.context() << '\n';
    590784        if (!msg.id().isEmpty())
    591785            out << QLatin1String("#. ts-id ") << msg.id() << '\n';
    592786
    593         if (!msg.fileName().isEmpty() && msg.fileName() != QLatin1String(MAGIC_OBSOLETE_REFERENCE)) {
     787        QString xrefs = msg.extra(QLatin1String("po-references"));
     788        if (!msg.fileName().isEmpty() || !xrefs.isEmpty()) {
    594789            QStringList refs;
    595790            foreach (const TranslatorMessage::Reference &ref, msg.allReferences())
    596791                refs.append(QString(QLatin1String("%2:%1"))
    597792                                    .arg(ref.lineNumber()).arg(ref.fileName()));
     793            if (!xrefs.isEmpty())
     794                refs << xrefs;
    598795            out << poWrappedEscapedLines(QLatin1String("#:"), true, refs.join(QLatin1String(" ")));
    599796        }
    600797
    601798        bool noWrap = false;
     799        bool skipFormat = false;
    602800        QStringList flags;
    603         if (msg.type() == TranslatorMessage::Unfinished)
     801        if (msg.type() == TranslatorMessage::Unfinished && msg.isTranslated())
    604802            flags.append(QLatin1String("fuzzy"));
    605803        TranslatorMessage::ExtraData::const_iterator itr =
    606804                msg.extras().find(QLatin1String("po-flags"));
    607805        if (itr != msg.extras().end()) {
    608             if (itr->split(QLatin1String(", ")).contains(QLatin1String("no-wrap")))
     806            QStringList atoms = itr->split(QLatin1String(", "));
     807            foreach (const QString &atom, atoms)
     808                if (atom.endsWith(str_format)) {
     809                    skipFormat = true;
     810                    break;
     811                }
     812            if (atoms.contains(QLatin1String("no-wrap")))
    609813                noWrap = true;
    610814            flags.append(*itr);
    611815        }
     816        if (!skipFormat) {
     817            QString source = msg.sourceText();
     818            // This is fuzzy logic, as we don't know whether the string is
     819            // actually used with QString::arg().
     820            for (int off = 0; (off = source.indexOf(QLatin1Char('%'), off)) >= 0; ) {
     821                if (++off >= source.length())
     822                    break;
     823                if (source.at(off) == QLatin1Char('n') || source.at(off).isDigit()) {
     824                    flags.append(QLatin1String("qt-format"));
     825                    break;
     826                }
     827            }
     828        }
    612829        if (!flags.isEmpty())
    613830            out << "#, " << flags.join(QLatin1String(", ")) << '\n';
     
    615832        QString prefix = QLatin1String("#| ");
    616833        if (!msg.oldComment().isEmpty())
    617             out << poEscapedString(prefix, QLatin1String("msgctxt"), noWrap, msg.oldComment());
     834            out << poEscapedString(prefix, QLatin1String("msgctxt"), noWrap,
     835                                   escapeComment(msg.oldComment(), qtContexts));
    618836        if (!msg.oldSourceText().isEmpty())
    619837            out << poEscapedString(prefix, QLatin1String("msgid"), noWrap, msg.oldSourceText());
     
    622840            out << poEscapedString(prefix, QLatin1String("msgid_plural"), noWrap, plural);
    623841        prefix = QLatin1String((msg.type() == TranslatorMessage::Obsolete) ? "#~ " : "");
    624         if (!msg.comment().isEmpty())
    625             out << poEscapedString(prefix, QLatin1String("msgctxt"), noWrap, msg.comment());
     842        if (!msg.context().isEmpty())
     843            out << poEscapedString(prefix, QLatin1String("msgctxt"), noWrap,
     844                                   escapeComment(msg.context(), true) + QLatin1Char('|')
     845                                   + escapeComment(msg.comment(), true));
     846        else if (!msg.comment().isEmpty())
     847            out << poEscapedString(prefix, QLatin1String("msgctxt"), noWrap,
     848                                   escapeComment(msg.comment(), qtContexts));
    626849        out << poEscapedString(prefix, QLatin1String("msgid"), noWrap, msg.sourceText());
    627850        if (!msg.isPlural()) {
    628851            QString transl = msg.translation();
    629             if (first) {
    630                 transl.remove(QRegExp(QLatin1String("\\bX-Language:[^\n]*\n")));
    631                 if (!translator.languageCode().isEmpty())
    632                     transl += QLatin1String("X-Language: ") + translator.languageCode() + QLatin1Char('\n');
    633             }
     852            transl.replace(QChar(Translator::BinaryVariantSeparator),
     853                           QChar(Translator::TextVariantSeparator));
    634854            out << poEscapedString(prefix, QLatin1String("msgstr"), noWrap, transl);
    635855        } else {
     
    647867            }
    648868        }
    649         first = false;
    650869    }
    651870    return ok;
     871}
     872
     873static bool savePOT(const Translator &translator, QIODevice &dev, ConversionData &cd)
     874{
     875    Translator ttor = translator;
     876    ttor.dropTranslations();
     877    return savePO(ttor, dev, cd);
    652878}
    653879
     
    662888    format.priority = 1;
    663889    Translator::registerFileFormat(format);
     890    format.extension = QLatin1String("pot");
     891    format.description = QObject::tr("GNU Gettext localization template files");
     892    format.loader = &loadPO;
     893    format.saver = &savePOT;
     894    format.fileType = Translator::FileFormat::TranslationSource;
     895    format.priority = -1;
     896    Translator::registerFileFormat(format);
    664897    return 1;
    665898}
  • trunk/tools/linguist/shared/profileevaluator.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    26082608{
    26092609    if (d->m_verbose && !d->m_skipLevel)
    2610         qWarning("%s", qPrintable(message));
     2610        fprintf(stderr, "%s\n", qPrintable(message));
    26112611}
    26122612
     
    26142614{
    26152615    if (!d->m_skipLevel)
    2616         qWarning("%s", qPrintable(message));
     2616        fprintf(stderr, "%s\n", qPrintable(message));
    26172617}
    26182618
     
    26202620{
    26212621    if (!d->m_skipLevel)
    2622         qWarning("%s", qPrintable(message));
     2622        fprintf(stderr, "%s\n", qPrintable(message));
    26232623}
    26242624
  • trunk/tools/linguist/shared/profileevaluator.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/proitems.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/proitems.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/proparserutils.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/qm.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    565565    QStringList numerusForms;
    566566    bool guessPlurals = true;
    567     if (getNumerusInfo(l, c, 0, &numerusForms))
     567    if (getNumerusInfo(l, c, 0, &numerusForms, 0))
    568568        guessPlurals = (numerusForms.count() == 1);
    569569
     
    705705    Translator::languageAndCountry(translator.languageCode(), &l, &c);
    706706    QByteArray rules;
    707     if (getNumerusInfo(l, c, &rules, 0))
     707    if (getNumerusInfo(l, c, &rules, 0, 0))
    708708        releaser.setNumerusRules(rules);
    709709    releaser.setCodecName(translator.codecName());
     
    774774        int generatedCount = finished + unfinished;
    775775        cd.appendError(QCoreApplication::translate("LRelease",
    776             "    Generated %n translation(s) (%1 finished and %2 unfinished)\n", 0,
     776            "    Generated %n translation(s) (%1 finished and %2 unfinished)", 0,
    777777            QCoreApplication::CodecForTr, generatedCount).arg(finished).arg(unfinished));
    778778        if (untranslated)
    779779            cd.appendError(QCoreApplication::translate("LRelease",
    780                 "    Ignored %n untranslated source text(s)\n", 0,
     780                "    Ignored %n untranslated source text(s)", 0,
    781781                QCoreApplication::CodecForTr, untranslated));
    782782    }
  • trunk/tools/linguist/shared/qph.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/simtexth.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/simtexth.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/translator.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4444#include "simtexth.h"
    4545
     46#include <iostream>
     47
    4648#include <stdio.h>
    4749#ifdef Q_OS_WIN
    48 #include <io.h> // required for _setmode, to avoid _O_TEXT streams...
    49 #include <fcntl.h> // for _O_BINARY
     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
    5057#endif
    5158
     
    214221#ifdef Q_OS_WIN
    215222        // QFile is broken for text files
     223# ifdef Q_OS_WINCE
     224        ::_setmode(stdin, _O_BINARY);
     225# else
    216226        ::_setmode(0, _O_BINARY);
     227# endif
    217228#endif
    218229        if (!file.open(stdin, QIODevice::ReadOnly)) {
     
    254265#ifdef Q_OS_WIN
    255266        // QFile is broken for text files
     267# ifdef Q_OS_WINCE
     268        ::_setmode(stdout, _O_BINARY);
     269# else
    256270        ::_setmode(1, _O_BINARY);
     271# endif
    257272#endif
    258273        if (!file.open(stdout, QIODevice::WriteOnly)) {
     
    574589{
    575590    if (!dupes.byId.isEmpty() || !dupes.byContents.isEmpty()) {
     591        std::cerr << "Warning: dropping duplicate messages in '" << qPrintable(fileName);
    576592        if (!verbose) {
    577             qWarning("Warning: dropping duplicate messages in '%s'\n(try -verbose for more info).",
    578                      qPrintable(fileName));
     593            std::cerr << "'\n(try -verbose for more info).\n";
    579594        } else {
    580             qWarning("Warning: dropping duplicate messages in '%s':", qPrintable(fileName));
     595            std::cerr << "':\n";
    581596            foreach (int i, dupes.byId)
    582                 qWarning("\n* ID: %s", qPrintable(message(i).id()));
     597                std::cerr << "\n* ID: " << qPrintable(message(i).id()) << std::endl;
    583598            foreach (int j, dupes.byContents) {
    584599                const TranslatorMessage &msg = message(j);
    585                 qWarning("\n* Context: %s\n* Source: %s",
    586                         qPrintable(msg.context()),
    587                         qPrintable(msg.sourceText()));
     600                std::cerr << "\n* Context: " << qPrintable(msg.context())
     601                          << "\n* Source: " << qPrintable(msg.sourceText()) << std::endl;
    588602                if (!msg.comment().isEmpty())
    589                     qWarning("* Comment: %s", qPrintable(msg.comment()));
     603                    std::cerr << "* Comment: " << qPrintable(msg.comment()) << std::endl;
    590604            }
    591             qWarning();
     605            std::cerr << std::endl;
    592606        }
    593607    }
     
    653667    if (l != QLocale::C) {
    654668        QStringList forms;
    655         if (getNumerusInfo(l, c, 0, &forms))
     669        if (getNumerusInfo(l, c, 0, &forms, 0))
    656670            numPlurals = forms.count(); // includes singular
    657671    }
     
    676690            "Removed plural forms as the target language has less "
    677691            "forms.\nIf this sounds wrong, possibly the target language is "
    678             "not set or recognized.\n"));
     692            "not set or recognized."));
    679693}
    680694
     
    725739    if (!codec) {
    726740        if (!name.isEmpty())
    727             qWarning("No QTextCodec for %s available. Using Latin1\n", name.constData());
     741            std::cerr << "No QTextCodec for " << name.constData() << " available. Using Latin1.\n";
    728742        m_codec = QTextCodec::codecForName("ISO-8859-1");
    729743    } else {
  • trunk/tools/linguist/shared/translator.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    9393
    9494    void appendError(const QString &error) { m_errors.append(error); }
    95     QString error() const { return  m_errors.join(QLatin1String("\n")); }
     95    QString error() const { return m_errors.isEmpty() ? QString() : m_errors.join(QLatin1String("\n")) + QLatin1Char('\n'); }
    9696    QStringList errors() const { return  m_errors; }
    9797    void clearErrors() { m_errors.clear(); }
     
    124124    Translator();
    125125
    126     bool load(const QString &filename, ConversionData &err, const QString &format /*= "auto"*/);
    127     bool save(const QString &filename, ConversionData &err, const QString &format /*= "auto"*/) const;
     126    bool load(const QString &filename, ConversionData &err, const QString &format /* = "auto" */);
     127    bool save(const QString &filename, ConversionData &err, const QString &format /* = "auto" */) const;
    128128    bool release(QFile *iod, ConversionData &cd) const;
    129129
     
    234234
    235235bool getNumerusInfo(QLocale::Language language, QLocale::Country country,
    236                            QByteArray *rules, QStringList *forms);
     236                    QByteArray *rules, QStringList *forms, const char **gettextRules);
    237237
    238238/*
  • trunk/tools/linguist/shared/translatormessage.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/translatormessage.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/ts.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/tools/linguist/shared/ts.dtd

    r561 r846  
    55 ! The location element is set as optional since it was introduced first in Qt 4.2.
    66 ! The userdata element is set as optional since it was introduced first in Qt 4.4.
    7  ! The source and translation elements are optional starting with version 3.0
    8  ! (Qt 4.6) to support S60 blank messages.
    97 !
    108  -->
     
    3735<!-- The encoding to use in the QM file by default. Default is ISO-8859-1. -->
    3836<!ELEMENT defaultcodec (#PCDATA) >
    39 <!ELEMENT context (name?, comment?, (context|message)+) >
     37<!ELEMENT context (name, comment?, (context|message)+) >
    4038<!ATTLIST context
    4139          encoding CDATA #IMPLIED>
    4240<!ELEMENT name %evilstring; >
    43 <!-- If "no", then the context nesting is for informational puposes only -->
    44 <!ATTLIST name
    45           nest (yes|no) "yes">
    4641<!-- This is "disambiguation" in the (new) API, or "msgctxt" in gettext speak -->
    4742<!ELEMENT comment %evilstring; >
     
    5449<!ELEMENT message (location*, source?, oldsource?, comment?, oldcomment?, extracomment?, translatorcomment?, translation?, userdata?, extra-**) >
    5550<!--
    56  ! If utf8 is true, the defaultcodec is overridden and the message is encoded
    57  ! in UTF-8 in the QM file.
     51 ! If utf8 is "true", the defaultcodec is overridden and the message is encoded
     52 ! in UTF-8 in the QM file. If it is "both", both source encodings are stored
     53 ! in the QM file.
    5854  -->
    5955<!ATTLIST message
    6056          id CDATA #IMPLIED
    61           utf8 (true|false) "false"
     57          utf8 (true|false|both) "false"
    6258          numerus (yes|no) "no">
    6359<!ELEMENT location EMPTY>
     
    10197<!ELEMENT numerusform (#PCDATA|byte|lengthvariant)* >
    10298<!ATTLIST numerusform
    103           plurality (nullar|singular|dual|trial|paucal|greaterpaucal|plural|greaterplural) #IMPLIED>
    10499          variants (yes|no) "no">
    105100<!ELEMENT lengthvariant %evilstring; >
    106 <!--
    107  ! The translation variants have a priority between 1 ("highest") and 9 ("lowest")
    108  ! Typically longer translations get a higher priority.
    109  ! If omitted, the order of appearance of the variants in the TS files is used.
    110   -->
    111 <!ATTLIST lengthvariant
    112           priority (1|2|3|4|5|6|7|8|9) #IMPLIED>
    113          
  • trunk/tools/linguist/shared/xliff.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5454
    5555
     56// The string value is historical and reflects the main purpose: Keeping
     57// obsolete entries separate from the magic file message (which both have
     58// no location information, but typically reside at opposite ends of the file).
     59#define MAGIC_OBSOLETE_REFERENCE "Obsolete_PO_entries"
     60
    5661QT_BEGIN_NAMESPACE
    5762
     
    504509        m_sourceLanguage = atts.value(QLatin1String("source-language"));
    505510        m_sourceLanguage.replace(QLatin1Char('-'), QLatin1Char('_'));
     511        if (m_sourceLanguage == QLatin1String("en"))
     512            m_sourceLanguage.clear();
    506513    } else if (localName == QLatin1String("group")) {
    507514        if (atts.value(QLatin1String("restype")) == QLatin1String(restypeContext)) {
     
    691698        return false;
    692699    }
     700    if (m_type == TranslatorMessage::Obsolete && m_refs.size() == 1
     701        && m_refs.at(0).fileName() == QLatin1String(MAGIC_OBSOLETE_REFERENCE))
     702        m_refs.clear();
    693703    TranslatorMessage msg(m_context, m_sources[0],
    694704                          m_comment, QString(), QString(), -1,
     
    760770    QList<QString> fileOrder;
    761771    foreach (const TranslatorMessage &msg, translator.messages()) {
    762         QHash<QString, QList<TranslatorMessage> > &file = messageOrder[msg.fileName()];
     772        QString fn = msg.fileName();
     773        if (fn.isEmpty() && msg.type() == TranslatorMessage::Obsolete)
     774            fn = QLatin1String(MAGIC_OBSOLETE_REFERENCE);
     775        QHash<QString, QList<TranslatorMessage> > &file = messageOrder[fn];
    763776        if (file.isEmpty())
    764             fileOrder.append(msg.fileName());
     777            fileOrder.append(fn);
    765778        QList<TranslatorMessage> &context = file[msg.context()];
    766779        if (context.isEmpty())
    767             contextOrder[msg.fileName()].append(msg.context());
     780            contextOrder[fn].append(msg.context());
    768781        context.append(msg);
    769782    }
Note: See TracChangeset for help on using the changeset viewer.