tools/linguist/lupdate/qdeclarative.cpp
changeset 37 758a864f9613
parent 33 3e2da88830cd
equal deleted inserted replaced
36:ef0373b55136 37:758a864f9613
    63 #include <iostream>
    63 #include <iostream>
    64 #include <cstdlib>
    64 #include <cstdlib>
    65 
    65 
    66 QT_BEGIN_NAMESPACE
    66 QT_BEGIN_NAMESPACE
    67 
    67 
       
    68 class LU {
       
    69     Q_DECLARE_TR_FUNCTIONS(LUpdate)
       
    70 };
       
    71 
    68 using namespace QDeclarativeJS;
    72 using namespace QDeclarativeJS;
       
    73 
       
    74 class Comment
       
    75 {
       
    76 public:
       
    77     Comment() : lastLine(-1) {}
       
    78     QString extracomment;
       
    79     QString msgid;
       
    80     TranslatorMessage::ExtraData extra;
       
    81     QString sourcetext;
       
    82     int lastLine;
       
    83 
       
    84     bool isValid() const
       
    85     { return !extracomment.isEmpty() || !msgid.isEmpty() || !sourcetext.isEmpty() || !extra.isEmpty(); }
       
    86 };
    69 
    87 
    70 class FindTrCalls: protected AST::Visitor
    88 class FindTrCalls: protected AST::Visitor
    71 {
    89 {
    72 public:
    90 public:
    73     void operator()(Translator *translator, const QString &fileName, AST::Node *node)
    91     void operator()(Translator *translator, const QString &fileName, AST::Node *node)
    75         m_translator = translator;
    93         m_translator = translator;
    76         m_fileName = fileName;
    94         m_fileName = fileName;
    77         m_component = QFileInfo(fileName).baseName();   //matches qsTr usage in QScriptEngine
    95         m_component = QFileInfo(fileName).baseName();   //matches qsTr usage in QScriptEngine
    78         accept(node);
    96         accept(node);
    79     }
    97     }
       
    98 
       
    99     QList<Comment> comments;
    80 
   100 
    81 protected:
   101 protected:
    82     using AST::Visitor::visit;
   102     using AST::Visitor::visit;
    83     using AST::Visitor::endVisit;
   103     using AST::Visitor::endVisit;
    84 
   104 
   112                         AST::ArgumentList *nNode = commentNode->next;
   132                         AST::ArgumentList *nNode = commentNode->next;
   113                         if (nNode)
   133                         if (nNode)
   114                             plural = true;
   134                             plural = true;
   115                     }
   135                     }
   116 
   136 
       
   137                     QString id;
       
   138                     QString extracomment;
       
   139                     TranslatorMessage::ExtraData extra;
       
   140                     Comment scomment = findComment(node->firstSourceLocation().startLine);
       
   141                     if (scomment.isValid()) {
       
   142                         extracomment = scomment.extracomment;
       
   143                         extra = scomment.extra;
       
   144                         id = scomment.msgid;
       
   145                     }
       
   146 
   117                     TranslatorMessage msg(m_component, source,
   147                     TranslatorMessage msg(m_component, source,
   118                         comment, QString(), m_fileName,
   148                         comment, QString(), m_fileName,
   119                         node->firstSourceLocation().startLine, QStringList(),
   149                         node->firstSourceLocation().startLine, QStringList(),
   120                         TranslatorMessage::Unfinished, plural);
   150                         TranslatorMessage::Unfinished, plural);
       
   151                     msg.setExtraComment(extracomment.simplified());
       
   152                     msg.setId(id);
       
   153                     msg.setExtras(extra);
   121                     m_translator->extend(msg);
   154                     m_translator->extend(msg);
   122                 }
   155                 }
   123             } else if (idExpr->name->asString() == QLatin1String("qsTranslate") ||
   156             } else if (idExpr->name->asString() == QLatin1String("qsTranslate") ||
   124                        idExpr->name->asString() == QLatin1String("QT_TRANSLATE_NOOP")) {
   157                        idExpr->name->asString() == QLatin1String("QT_TRANSLATE_NOOP")) {
   125                 if (node->arguments && AST::cast<AST::StringLiteral *>(node->arguments->expression)) {
   158                 if (node->arguments && AST::cast<AST::StringLiteral *>(node->arguments->expression)) {
   138                         if (!createString(binary))
   171                         if (!createString(binary))
   139                             m_bSource.clear();
   172                             m_bSource.clear();
   140                     }
   173                     }
   141                     if (!literal && m_bSource.isEmpty())
   174                     if (!literal && m_bSource.isEmpty())
   142                         return;
   175                         return;
       
   176 
       
   177                     QString id;
       
   178                     QString extracomment;
       
   179                     TranslatorMessage::ExtraData extra;
       
   180                     Comment scomment = findComment(node->firstSourceLocation().startLine);
       
   181                     if (scomment.isValid()) {
       
   182                         extracomment = scomment.extracomment;
       
   183                         extra = scomment.extra;
       
   184                         id = scomment.msgid;
       
   185                     }
       
   186 
   143                     source = literal ? literal->value->asString() : m_bSource;
   187                     source = literal ? literal->value->asString() : m_bSource;
   144                     AST::ArgumentList *commentNode = sourceNode->next;
   188                     AST::ArgumentList *commentNode = sourceNode->next;
   145                     if (commentNode && AST::cast<AST::StringLiteral *>(commentNode->expression)) {
   189                     if (commentNode && AST::cast<AST::StringLiteral *>(commentNode->expression)) {
   146                         literal = AST::cast<AST::StringLiteral *>(commentNode->expression);
   190                         literal = AST::cast<AST::StringLiteral *>(commentNode->expression);
   147                         comment = literal->value->asString();
   191                         comment = literal->value->asString();
   153 
   197 
   154                     TranslatorMessage msg(context, source,
   198                     TranslatorMessage msg(context, source,
   155                         comment, QString(), m_fileName,
   199                         comment, QString(), m_fileName,
   156                         node->firstSourceLocation().startLine, QStringList(),
   200                         node->firstSourceLocation().startLine, QStringList(),
   157                         TranslatorMessage::Unfinished, plural);
   201                         TranslatorMessage::Unfinished, plural);
       
   202                     msg.setExtraComment(extracomment.simplified());
       
   203                     msg.setId(id);
       
   204                     msg.setExtras(extra);
   158                     m_translator->extend(msg);
   205                     m_translator->extend(msg);
   159                 }
   206                 }
   160 
   207             } else if (idExpr->name->asString() == QLatin1String("qsTrId") ||
       
   208                        idExpr->name->asString() == QLatin1String("QT_TRID_NOOP")) {
       
   209                 if (!node->arguments)
       
   210                     return;
       
   211 
       
   212                 AST::StringLiteral *literal = AST::cast<AST::StringLiteral *>(node->arguments->expression);
       
   213                 if (literal) {
       
   214 
       
   215                     QString extracomment;
       
   216                     QString sourcetext;
       
   217                     TranslatorMessage::ExtraData extra;
       
   218                     Comment comment = findComment(node->firstSourceLocation().startLine);
       
   219                     if (comment.isValid()) {
       
   220                         extracomment = comment.extracomment;
       
   221                         sourcetext = comment.sourcetext;
       
   222                         extra = comment.extra;
       
   223                     }
       
   224 
       
   225                     const QString id = literal->value->asString();
       
   226                     bool plural = node->arguments->next;
       
   227 
       
   228                     TranslatorMessage msg(QString(), QString(),
       
   229                         QString(), QString(), m_fileName,
       
   230                         node->firstSourceLocation().startLine, QStringList(),
       
   231                         TranslatorMessage::Unfinished, plural);
       
   232                     msg.setExtraComment(extracomment.simplified());
       
   233                     msg.setId(id);
       
   234                     msg.setExtras(extra);
       
   235                     m_translator->extend(msg);
       
   236                 }
   161             }
   237             }
   162         }
   238         }
   163     }
   239     }
   164 
   240 
   165 private:
   241 private:
   166     bool createString(AST::BinaryExpression *b) {
   242     bool createString(AST::BinaryExpression *b)
       
   243     {
   167         if (!b || b->op != 0)
   244         if (!b || b->op != 0)
   168             return false;
   245             return false;
   169         AST::BinaryExpression *l = AST::cast<AST::BinaryExpression *>(b->left);
   246         AST::BinaryExpression *l = AST::cast<AST::BinaryExpression *>(b->left);
   170         AST::BinaryExpression *r = AST::cast<AST::BinaryExpression *>(b->right);
   247         AST::BinaryExpression *r = AST::cast<AST::BinaryExpression *>(b->right);
   171         AST::StringLiteral *ls = AST::cast<AST::StringLiteral *>(b->left);
   248         AST::StringLiteral *ls = AST::cast<AST::StringLiteral *>(b->left);
   185             m_bSource.append(rs->value->asString());
   262             m_bSource.append(rs->value->asString());
   186 
   263 
   187         return true;
   264         return true;
   188     }
   265     }
   189 
   266 
       
   267     Comment findComment(int loc)
       
   268     {
       
   269         if (comments.isEmpty())
       
   270             return Comment();
       
   271 
       
   272         int i = 0;
       
   273         int commentLoc = comments.at(i).lastLine;
       
   274         while (commentLoc <= loc) {
       
   275             if (commentLoc == loc)
       
   276                 return comments.at(i);
       
   277             if (i == comments.count()-1)
       
   278                 break;
       
   279             commentLoc = comments.at(++i).lastLine;
       
   280         }
       
   281         return Comment();
       
   282     }
       
   283 
   190     Translator *m_translator;
   284     Translator *m_translator;
   191     QString m_fileName;
   285     QString m_fileName;
   192     QString m_component;
   286     QString m_component;
   193     QString m_bSource;
   287     QString m_bSource;
   194 };
   288 };
   234         errorString += error;
   328         errorString += error;
   235     }
   329     }
   236     return errorString;
   330     return errorString;
   237 }
   331 }
   238 
   332 
       
   333 bool processComment(const QChar *chars, int length, Comment &comment)
       
   334 {
       
   335     // Try to match the logic of the QtScript parser.
       
   336     if (!length)
       
   337         return comment.isValid();
       
   338     if (*chars == QLatin1Char(':') && chars[1].isSpace()) {
       
   339         comment.extracomment += QString(chars+1, length-1);
       
   340     } else if (*chars == QLatin1Char('=') && chars[1].isSpace()) {
       
   341         comment.msgid = QString(chars+2, length-2).simplified();
       
   342     } else if (*chars == QLatin1Char('~') && chars[1].isSpace()) {
       
   343         QString text = QString(chars+2, length-2).trimmed();
       
   344         int k = text.indexOf(QLatin1Char(' '));
       
   345         if (k > -1)
       
   346             comment.extra.insert(text.left(k), text.mid(k + 1).trimmed());
       
   347     } else if (*chars == QLatin1Char('%') && chars[1].isSpace()) {
       
   348         comment.sourcetext.reserve(comment.sourcetext.length() + length-2);
       
   349         ushort *ptr = (ushort *)comment.sourcetext.data() + comment.sourcetext.length();
       
   350         int p = 2, c;
       
   351         forever {
       
   352             if (p >= length)
       
   353                 break;
       
   354             c = chars[p++].unicode();
       
   355             if (isspace(c))
       
   356                 continue;
       
   357             if (c != '"')
       
   358                 break;
       
   359             forever {
       
   360                 if (p >= length)
       
   361                     break;
       
   362                 c = chars[p++].unicode();
       
   363                 if (c == '"')
       
   364                     break;
       
   365                 if (c == '\\') {
       
   366                     if (p >= length)
       
   367                         break;
       
   368                     c = chars[p++].unicode();
       
   369                     if (c == '\n')
       
   370                         break;
       
   371                     *ptr++ = '\\';
       
   372                 }
       
   373                 *ptr++ = c;
       
   374             }
       
   375         }
       
   376         comment.sourcetext.resize(ptr - (ushort *)comment.sourcetext.data());
       
   377     }
       
   378     return comment.isValid();
       
   379 }
       
   380 
   239 bool loadQml(Translator &translator, const QString &filename, ConversionData &cd)
   381 bool loadQml(Translator &translator, const QString &filename, ConversionData &cd)
   240 {
   382 {
   241     cd.m_sourceFileName = filename;
   383     cd.m_sourceFileName = filename;
   242     QFile file(filename);
   384     QFile file(filename);
   243     if (!file.open(QIODevice::ReadOnly)) {
   385     if (!file.open(QIODevice::ReadOnly)) {
   244         cd.appendError(QString::fromLatin1("Cannot open %1: %2")
   386         cd.appendError(LU::tr("Cannot open %1: %2").arg(filename, file.errorString()));
   245             .arg(filename, file.errorString()));
       
   246         return false;
   387         return false;
   247     }
   388     }
   248 
   389 
   249     const QString code = QTextStream(&file).readAll();
   390     const QString code = QTextStream(&file).readAll();
   250 
   391 
   258     lexer.setCode(code, /*line = */ 1);
   399     lexer.setCode(code, /*line = */ 1);
   259     driver.setLexer(&lexer);
   400     driver.setLexer(&lexer);
   260 
   401 
   261     if (parser.parse()) {
   402     if (parser.parse()) {
   262         FindTrCalls trCalls;
   403         FindTrCalls trCalls;
       
   404 
       
   405         // build up a list of comments that contain translation information.
       
   406         for (int i = 0; i < driver.comments().size(); ++i) {
       
   407             AST::SourceLocation loc = driver.comments().at(i);
       
   408             QString commentStr = code.mid(loc.offset, loc.length);
       
   409 
       
   410             if (trCalls.comments.isEmpty() || trCalls.comments.last().lastLine != int(loc.startLine)) {
       
   411                 Comment comment;
       
   412                 comment.lastLine = loc.startLine+1;
       
   413                 if (processComment(commentStr.constData(), commentStr.length(), comment))
       
   414                     trCalls.comments.append(comment);
       
   415             } else {
       
   416                 Comment &lastComment = trCalls.comments.last();
       
   417                 lastComment.lastLine += 1;
       
   418                 processComment(commentStr.constData(), commentStr.length(), lastComment);
       
   419             }
       
   420         }
       
   421 
       
   422         //find all tr calls in the code
   263         trCalls(&translator, filename, parser.ast());
   423         trCalls(&translator, filename, parser.ast());
   264     } else {
   424     } else {
   265         QString error = createErrorString(filename, code, parser);
   425         QString error = createErrorString(filename, code, parser);
   266         cd.appendError(error);
   426         cd.appendError(error);
   267         return false;
   427         return false;