summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--development/translation/opie-lupdate/fetchtr.cpp55
-rw-r--r--development/translation/opie-lupdate/main.cpp11
-rw-r--r--development/translation/opie-lupdate/merge.cpp6
-rw-r--r--development/translation/opie-lupdate/numberh.cpp24
-rw-r--r--development/translation/opie-lupdate/sametexth.cpp6
-rw-r--r--development/translation/shared/metatranslator.cpp34
-rw-r--r--development/translation/shared/metatranslator.h16
-rw-r--r--development/translation/shared/opie.h2
-rw-r--r--development/translation/shared/proparser.cpp103
-rw-r--r--development/translation/shared/proparser.h8
10 files changed, 222 insertions, 43 deletions
diff --git a/development/translation/opie-lupdate/fetchtr.cpp b/development/translation/opie-lupdate/fetchtr.cpp
index d1f5881..a137628 100644
--- a/development/translation/opie-lupdate/fetchtr.cpp
+++ b/development/translation/opie-lupdate/fetchtr.cpp
@@ -1,284 +1,311 @@
/**********************************************************************
** Copyright (C) 2000 Trolltech AS. All rights reserved.
**
** This file is part of Qt Linguist.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include <metatranslator.h>
#include <qfile.h>
#include <qregexp.h>
#include <qstring.h>
#include <qtextstream.h>
#include <qvaluestack.h>
#include <qxml.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
/* qmake ignore Q_OBJECT */
static const char MagicComment[] = "TRANSLATOR ";
static QMap<QCString, int> needs_Q_OBJECT;
static QMap<QCString, int> lacks_Q_OBJECT;
/*
The first part of this source file is the C++ tokenizer. We skip
most of C++; the only tokens that interest us are defined here.
Thus, the code fragment
int main()
{
printf( "Hello, world!\n" );
return 0;
}
is broken down into the following tokens (Tok_ omitted):
Ident Ident LeftParen RightParen
LeftBrace
Ident LeftParen String RightParen Semicolon
return Semicolon
RightBrace.
The 0 doesn't produce any token.
*/
enum { Tok_Eof, Tok_class, Tok_namespace, Tok_return, Tok_tr,
Tok_trUtf8, Tok_translate, Tok_Q_OBJECT, Tok_Ident,
Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon,
Tok_Gulbrandsen, Tok_LeftBrace, Tok_RightBrace, Tok_LeftParen,
Tok_RightParen, Tok_Comma, Tok_Semicolon };
/*
The tokenizer maintains the following global variables. The names
should be self-explanatory.
*/
static QCString yyFileName;
static int yyCh;
static char yyIdent[128];
static size_t yyIdentLen;
static char yyComment[65536];
static size_t yyCommentLen;
static char yyString[16384];
static size_t yyStringLen;
static QValueStack<int> yySavedBraceDepth;
+static QValueStack<int> yySavedParenDepth;
static int yyBraceDepth;
static int yyParenDepth;
static int yyLineNo;
static int yyCurLineNo;
+static int yyBraceLineNo;
+static int yyParenLineNo;
// the file to read from (if reading from a file)
static FILE *yyInFile;
// the string to read from and current position in the string (otherwise)
static QString yyInStr;
static int yyInPos;
static int (*getChar)();
static int getCharFromFile()
{
int c = getc( yyInFile );
if ( c == '\n' )
yyCurLineNo++;
return c;
}
static int getCharFromString()
{
if ( yyInPos == (int) yyInStr.length() ) {
return EOF;
} else {
return yyInStr[yyInPos++].latin1();
}
}
static void startTokenizer( const char *fileName, int (*getCharFunc)() )
{
yyInPos = 0;
getChar = getCharFunc;
yyFileName = fileName;
yyCh = getChar();
yySavedBraceDepth.clear();
+ yySavedParenDepth.clear();
yyBraceDepth = 0;
yyParenDepth = 0;
yyCurLineNo = 1;
+ yyBraceLineNo = 1;
+ yyParenLineNo = 1;
}
static int getToken()
{
const char tab[] = "abfnrtv";
const char backTab[] = "\a\b\f\n\r\t\v";
uint n;
yyIdentLen = 0;
yyCommentLen = 0;
yyStringLen = 0;
while ( yyCh != EOF ) {
yyLineNo = yyCurLineNo;
if ( isalpha(yyCh) || yyCh == '_' ) {
do {
if ( yyIdentLen < sizeof(yyIdent) - 1 )
yyIdent[yyIdentLen++] = (char) yyCh;
yyCh = getChar();
} while ( isalnum(yyCh) || yyCh == '_' );
yyIdent[yyIdentLen] = '\0';
switch ( yyIdent[0] ) {
case 'Q':
if ( strcmp(yyIdent + 1, "_OBJECT") == 0 ) {
return Tok_Q_OBJECT;
} else if ( strcmp(yyIdent + 1, "T_TR_NOOP") == 0 ) {
return Tok_tr;
} else if ( strcmp(yyIdent + 1, "T_TRANSLATE_NOOP") == 0 ) {
return Tok_translate;
}
break;
case 'T':
// TR() for when all else fails
if ( qstricmp(yyIdent + 1, "R") == 0 )
return Tok_tr;
break;
case 'c':
if ( strcmp(yyIdent + 1, "lass") == 0 )
return Tok_class;
break;
+ case 'f':
+ /*
+ QTranslator::findMessage() has the same parameters as
+ QApplication::translate().
+ */
+ if ( strcmp(yyIdent + 1, "indMessage") == 0 )
+ return Tok_translate;
+ break;
+ case 'i':
+ /* FOR KDE APPS */
+ if ( strcmp( yyIdent + 1, "8n") == 0 )
+ return Tok_translate;
+ break;
case 'n':
if ( strcmp(yyIdent + 1, "amespace") == 0 )
return Tok_namespace;
break;
case 'r':
if ( strcmp(yyIdent + 1, "eturn") == 0 )
return Tok_return;
break;
case 's':
if ( strcmp(yyIdent + 1, "truct") == 0 )
return Tok_class;
break;
- case 'i':
- if( strcmp(yyIdent + 1, "18n") == 0 )
- return Tok_tr;
case 't':
if ( strcmp(yyIdent + 1, "r") == 0 ) {
return Tok_tr;
} else if ( qstrcmp(yyIdent + 1, "rUtf8") == 0 ) {
return Tok_trUtf8;
} else if ( qstrcmp(yyIdent + 1, "ranslate") == 0 ) {
return Tok_translate;
}
}
return Tok_Ident;
} else {
switch ( yyCh ) {
case '#':
/*
Early versions of lupdate complained about
unbalanced braces in the following code:
#ifdef ALPHA
while ( beta ) {
#else
while ( gamma ) {
#endif
delta;
}
The code contains, indeed, two opening braces for
one closing brace; yet there's no reason to panic.
The solution is to remember yyBraceDepth as it was
when #if, #ifdef or #ifndef was met, and to set
yyBraceDepth to that value when meeting #elif or
#else.
*/
do {
yyCh = getChar();
} while ( isspace(yyCh) && yyCh != '\n' );
switch ( yyCh ) {
case 'i':
yyCh = getChar();
if ( yyCh == 'f' ) {
// if, ifdef, ifndef
yySavedBraceDepth.push( yyBraceDepth );
+ yySavedParenDepth.push( yyParenDepth );
}
break;
case 'e':
yyCh = getChar();
if ( yyCh == 'l' ) {
// elif, else
- if ( !yySavedBraceDepth.isEmpty() )
+ if ( !yySavedBraceDepth.isEmpty() ) {
yyBraceDepth = yySavedBraceDepth.top();
+ yyParenDepth = yySavedParenDepth.top();
+ }
} else if ( yyCh == 'n' ) {
// endif
- if ( !yySavedBraceDepth.isEmpty() )
+ if ( !yySavedBraceDepth.isEmpty() ) {
yySavedBraceDepth.pop();
+ yySavedParenDepth.pop();
+ }
}
}
while ( isalnum(yyCh) || yyCh == '_' )
yyCh = getChar();
break;
case '/':
yyCh = getChar();
if ( yyCh == '/' ) {
do {
yyCh = getChar();
} while ( yyCh != EOF && yyCh != '\n' );
} else if ( yyCh == '*' ) {
bool metAster = FALSE;
bool metAsterSlash = FALSE;
while ( !metAsterSlash ) {
yyCh = getChar();
if ( yyCh == EOF ) {
fprintf( stderr,
"%s: Unterminated C++ comment starting at"
" line %d\n",
(const char *) yyFileName, yyLineNo );
yyComment[yyCommentLen] = '\0';
return Tok_Comment;
}
if ( yyCommentLen < sizeof(yyComment) - 1 )
yyComment[yyCommentLen++] = (char) yyCh;
if ( yyCh == '*' )
metAster = TRUE;
else if ( metAster && yyCh == '/' )
metAsterSlash = TRUE;
else
metAster = FALSE;
}
yyCh = getChar();
yyCommentLen -= 2;
yyComment[yyCommentLen] = '\0';
return Tok_Comment;
}
break;
case '"':
yyCh = getChar();
while ( yyCh != EOF && yyCh != '\n' && yyCh != '"' ) {
if ( yyCh == '\\' ) {
yyCh = getChar();
@@ -311,108 +338,116 @@ static int getToken()
yyString[yyStringLen++] = ( p == 0 ) ?
(char) yyCh : backTab[p - tab];
yyCh = getChar();
}
} else {
if ( yyStringLen < sizeof(yyString) - 1 )
yyString[yyStringLen++] = (char) yyCh;
yyCh = getChar();
}
}
yyString[yyStringLen] = '\0';
if ( yyCh != '"' )
qWarning( "%s:%d: Unterminated C++ string",
(const char *) yyFileName, yyLineNo );
if ( yyCh == EOF ) {
return Tok_Eof;
} else {
yyCh = getChar();
return Tok_String;
}
break;
case '-':
yyCh = getChar();
if ( yyCh == '>' ) {
yyCh = getChar();
return Tok_Arrow;
}
break;
case ':':
yyCh = getChar();
if ( yyCh == ':' ) {
yyCh = getChar();
return Tok_Gulbrandsen;
}
return Tok_Colon;
case '\'':
yyCh = getChar();
if ( yyCh == '\\' )
yyCh = getChar();
do {
yyCh = getChar();
} while ( yyCh != EOF && yyCh != '\'' );
yyCh = getChar();
break;
case '{':
+ if (yyBraceDepth == 0)
+ yyBraceLineNo = yyCurLineNo;
yyBraceDepth++;
yyCh = getChar();
return Tok_LeftBrace;
case '}':
+ if (yyBraceDepth == 0)
+ yyBraceLineNo = yyCurLineNo;
yyBraceDepth--;
yyCh = getChar();
return Tok_RightBrace;
case '(':
+ if (yyParenDepth == 0)
+ yyParenLineNo = yyCurLineNo;
yyParenDepth++;
yyCh = getChar();
return Tok_LeftParen;
case ')':
+ if (yyParenDepth == 0)
+ yyParenLineNo = yyCurLineNo;
yyParenDepth--;
yyCh = getChar();
return Tok_RightParen;
case ',':
yyCh = getChar();
return Tok_Comma;
case ';':
yyCh = getChar();
return Tok_Semicolon;
default:
yyCh = getChar();
}
}
}
return Tok_Eof;
}
/*
The second part of this source file is the parser. It accomplishes
a very easy task: It finds all strings inside a tr() or translate()
call, and possibly finds out the context of the call. It supports
three cases: (1) the context is specified, as in
FunnyDialog::tr("Hello") or translate("FunnyDialog", "Hello");
(2) the call appears within an inlined function; (3) the call
appears within a function defined outside the class definition.
*/
static int yyTok;
static bool match( int t )
{
bool matches = ( yyTok == t );
if ( matches )
yyTok = getToken();
return matches;
}
static bool matchString( QCString *s )
{
bool matches = ( yyTok == Tok_String );
*s = "";
while ( yyTok == Tok_String ) {
*s += yyString;
yyTok = getToken();
}
return matches;
}
@@ -576,104 +611,104 @@ static void parse( MetaTranslator *tor, const char *initialContext,
*/
k = 0;
while ( (k = context.find("::", k)) != -1 ) {
qualifiedContexts.insert( context.mid(k + 2), context );
k++;
}
}
yyTok = getToken();
break;
case Tok_Arrow:
yyTok = getToken();
if ( yyTok == Tok_tr || yyTok == Tok_trUtf8 )
qWarning( "%s:%d: Cannot invoke tr() like this",
(const char *) yyFileName, yyLineNo );
break;
case Tok_Gulbrandsen:
// at top level?
if ( yyBraceDepth == (int) namespaces.count() && yyParenDepth == 0 )
functionContext = prefix;
yyTok = getToken();
break;
case Tok_RightBrace:
case Tok_Semicolon:
if ( yyBraceDepth >= 0 &&
yyBraceDepth + 1 == (int) namespaces.count() )
namespaces.remove( namespaces.fromLast() );
if ( yyBraceDepth == (int) namespaces.count() ) {
if ( missing_Q_OBJECT ) {
if ( needs_Q_OBJECT.contains(functionContext) ) {
qWarning( "%s:%d: Class '%s' lacks Q_OBJECT macro",
(const char *) yyFileName, yyLineNo,
(const char *) functionContext );
} else {
lacks_Q_OBJECT.insert( functionContext, 0 );
}
}
functionContext = defaultContext;
missing_Q_OBJECT = FALSE;
}
yyTok = getToken();
break;
default:
yyTok = getToken();
}
}
if ( yyBraceDepth != 0 )
fprintf( stderr,
- "%s: Unbalanced braces in C++ code (or abuse of the C++"
+ "%s:%d: Unbalanced braces in C++ code (or abuse of the C++"
" preprocessor)\n",
- (const char *) yyFileName );
- if ( yyParenDepth != 0 )
+ (const char *)yyFileName, yyBraceLineNo );
+ else if ( yyParenDepth != 0 )
fprintf( stderr,
- "%s: Unbalanced parentheses in C++ code (or abuse of the C++"
+ "%s:%d: Unbalanced parentheses in C++ code (or abuse of the C++"
" preprocessor)\n",
- (const char *) yyFileName );
+ (const char *)yyFileName, yyParenLineNo );
}
void fetchtr_cpp( const char *fileName, MetaTranslator *tor,
const char *defaultContext, bool mustExist )
{
yyInFile = fopen( fileName, "r" );
if ( yyInFile == 0 ) {
if ( mustExist )
fprintf( stderr,
"lupdate error: Cannot open C++ source file '%s': %s\n",
fileName, strerror(errno) );
return;
}
startTokenizer( fileName, getCharFromFile );
parse( tor, 0, defaultContext );
fclose( yyInFile );
}
/*
In addition to C++, we support Qt Designer UI files.
*/
/*
Fetches tr() calls in C++ code in UI files (inside "<function>"
tag). This mechanism is obsolete.
*/
void fetchtr_inlined_cpp( const char *fileName, const QString& in,
MetaTranslator *tor, const char *context )
{
yyInStr = in;
startTokenizer( fileName, getCharFromString );
parse( tor, context, 0 );
yyInStr = QString::null;
}
class UiHandler : public QXmlDefaultHandler
{
public:
UiHandler( MetaTranslator *translator, const char *fileName )
: tor( translator ), fname( fileName ), comment( "" ) { }
virtual bool startElement( const QString& namespaceURI,
const QString& localName, const QString& qName,
const QXmlAttributes& atts );
virtual bool endElement( const QString& namespaceURI,
const QString& localName, const QString& qName );
virtual bool characters( const QString& ch );
diff --git a/development/translation/opie-lupdate/main.cpp b/development/translation/opie-lupdate/main.cpp
index ce65e7a..bf16fd7 100644
--- a/development/translation/opie-lupdate/main.cpp
+++ b/development/translation/opie-lupdate/main.cpp
@@ -17,185 +17,194 @@
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include <metatranslator.h>
#include <proparser.h>
#include <opie.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qtextstream.h>
#include <errno.h>
#include <string.h>
// defined in fetchtr.cpp
extern void fetchtr_cpp( const char *fileName, MetaTranslator *tor,
const char *defaultContext, bool mustExist );
extern void fetchtr_ui( const char *fileName, MetaTranslator *tor,
const char *defaultContext, bool mustExist );
// defined in merge.cpp
extern void merge( MetaTranslator *tor, const MetaTranslator *virginTor,
bool verbose );
typedef QValueList<MetaTranslatorMessage> TML;
static const char* LUPDATE_VERSION = "0.1";
static void printUsage()
{
fprintf( stderr, "Usage:\n"
" opie-lupdate [options] project-file\n"
" opie-lupdate [options] source-files -ts ts-files\n"
"Options:\n"
" -opie The OPIE base dir if not supplied $OPIEDIR will be taken\n"
" -help Display this information and exit\n"
" -noobsolete\n"
" Drop all obsolete strings\n"
" -verbose\n"
" Explain what is being done\n"
" -version\n"
" Display the version of lupdate and exit\n" );
}
+/*static QString opie_escape( const QString& str ) {
+ QString ret = str.stripWhiteSpace();
+ qWarning(ret);
+ if ( ret.startsWith("$$(OPIEDIR)") )
+ ret = ret.replace("$$(OPIEDIR)", OPIE::self()->opieDir() );
+ qWarning(ret);
+ return ret;
+ }*/
+
static void updateTsFiles( const MetaTranslator& fetchedTor,
const QString& opiedir,
const QStringList& languages,
const QString& basename,
const QString& codec,
bool noObsolete, bool verbose )
{
QStringList::ConstIterator it = languages.begin();
for ( ; it != languages.end(); ++it ) {
QString fileName = opiedir + "/i18n/" + (*it) + "/" + basename;
MetaTranslator tor;
tor.load( fileName );
if ( !codec.isEmpty() )
tor.setCodec( codec );
if ( verbose )
fprintf( stderr, "Updating '%s'...\n", fileName.latin1() );
merge( &tor, &fetchedTor, verbose );
if ( noObsolete )
tor.stripObsoleteMessages();
tor.stripEmptyContexts();
if ( !tor.save(fileName) )
fprintf( stderr, "lupdate error: Cannot save '%s': %s\n",
fileName.latin1(), strerror(errno) );
}
}
int main( int argc, char **argv )
{
QString defaultContext = "@default";
MetaTranslator fetchedTor;
QCString codec;
QStringList tsFileNames;
QString opiedir;
QString translationBase;
QString target;
bool verbose = FALSE;
bool noObsolete = FALSE;
bool metSomething = FALSE;
bool isLib = FALSE;
int numFiles = 0;
int i;
QStringList languageList = OPIE::self()->languageList(opiedir);
for ( i = 1; i < argc; i++ ) {
if ( qstrcmp(argv[i], "-help") == 0 ) {
printUsage();
return 0;
} else if ( qstrcmp(argv[i], "-noobsolete") == 0 ) {
noObsolete = TRUE;
continue;
} else if ( qstrcmp(argv[i], "-verbose") == 0 ) {
verbose = TRUE;
continue;
} else if ( qstrcmp(argv[i], "-version") == 0 ) {
fprintf( stderr, "lupdate version %s\n", LUPDATE_VERSION );
return 0;
} else if ( qstrcmp(argv[i], "-opie") == 0 ) {
if( i+1 < argc ) {
opiedir = argv[i+1];
languageList = OPIE::self()->languageList(opiedir);
}
i++; // UGLY but we want to skip the next argument
continue;
}
numFiles++;
QString fullText;
QFile f( argv[i] );
if ( !f.open(IO_ReadOnly) ) {
fprintf( stderr, "lupdate error: Cannot open file '%s': %s\n",
argv[i], strerror(errno) );
return 1;
}
QTextStream t( &f );
fullText = t.read();
f.close();
fetchedTor = MetaTranslator();
codec.truncate( 0 );
tsFileNames.clear();
isLib = FALSE;
- QMap<QString, QString> tagMap = proFileTagMap( fullText );
+ QMap<QString, QString> tagMap = proFileTagMap( fullText, OPIE::self()->opieDir() );
QMap<QString, QString>::Iterator it;
for ( it = tagMap.begin(); it != tagMap.end(); ++it ) {
QStringList toks = QStringList::split( ' ', it.data() );
QStringList::Iterator t;
for ( t = toks.begin(); t != toks.end(); ++t ) {
if ( it.key() == "HEADERS" || it.key() == "SOURCES" ) {
fetchtr_cpp( *t, &fetchedTor, defaultContext, TRUE );
metSomething = TRUE;
} else if ( it.key() == "INTERFACES" ||
it.key() == "FORMS" ) {
fetchtr_ui( *t, &fetchedTor, defaultContext, TRUE );
fetchtr_cpp( *t + ".h", &fetchedTor, defaultContext,
FALSE );
metSomething = TRUE;
} else if ( it.key() == "TRANSLATIONS" ) {
// we do not care for that attribute anymore
//tsFileNames.append( *t );
metSomething = TRUE;
} else if ( it.key() == "CODEC" ) {
codec = (*t).latin1();
} else if ( it.key() == "TARGET" ) {
target = *t;
metSomething = TRUE;
} else if ( it.key() == "TEMPLATE" ) {
if ( (*t).stripWhiteSpace().lower() == "lib" )
isLib = true;
}
}
}
/**
* We know the $OPIEDIR or have opiedir
* we've a list of languages (de,en,gb,foo,bar)
* we've got the TARGET and we no it's the lib
* so let's do that
* $OPIEDIR/language[i]/ifLibAppendLib$TARGET.ts
*/
qWarning("TARGET %s IsLib:%d", target.latin1(), isLib );
qWarning("LANGS %s", languageList.join(";").latin1() );
qWarning("OPIEDIR %s", OPIE::self()->opieDir(opiedir).latin1() );
if (isLib )
target.prepend("lib");
target += ".ts";
updateTsFiles( fetchedTor, OPIE::self()->opieDir(opiedir),
languageList, target, codec, noObsolete, verbose );
if ( !metSomething ) {
diff --git a/development/translation/opie-lupdate/merge.cpp b/development/translation/opie-lupdate/merge.cpp
index a96104e..3001d4b 100644
--- a/development/translation/opie-lupdate/merge.cpp
+++ b/development/translation/opie-lupdate/merge.cpp
@@ -1,62 +1,68 @@
/**********************************************************************
** Copyright (C) 2000 Trolltech AS. All rights reserved.
**
** This file is part of Qt Linguist.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include <metatranslator.h>
// defined in numberh.cpp
extern void applyNumberHeuristic( MetaTranslator *tor, bool verbose );
// defined in sametexth.cpp
extern void applySameTextHeuristic( MetaTranslator *tor, bool verbose );
typedef QValueList<MetaTranslatorMessage> TML;
/*
Merges two MetaTranslator objects into the first one. The first one
is a set of source texts and translations for a previous version of
the internationalized program; the second one is a set of fresh
source texts newly extracted from the source code, without any
translation yet.
*/
void merge( MetaTranslator *tor, const MetaTranslator *virginTor, bool verbose )
{
int known = 0;
int neww = 0;
int obsoleted = 0;
TML all = tor->messages();
TML::Iterator it;
/*
The types of all the messages from the vernacular translator
are updated according to the virgin translator.
*/
for ( it = all.begin(); it != all.end(); ++it ) {
MetaTranslatorMessage::Type newType;
MetaTranslatorMessage m = *it;
// skip context comment
if ( !QCString((*it).sourceText()).isEmpty() ) {
if ( !virginTor->contains((*it).context(), (*it).sourceText(),
(*it).comment()) ) {
newType = MetaTranslatorMessage::Obsolete;
if ( m.type() != MetaTranslatorMessage::Obsolete )
obsoleted++;
} else {
switch ( m.type() ) {
diff --git a/development/translation/opie-lupdate/numberh.cpp b/development/translation/opie-lupdate/numberh.cpp
index f7b7bf8..2f12c3d 100644
--- a/development/translation/opie-lupdate/numberh.cpp
+++ b/development/translation/opie-lupdate/numberh.cpp
@@ -1,96 +1,102 @@
/**********************************************************************
** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
**
** This file is part of Qt Linguist.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include <metatranslator.h>
#include <qmemarray.h>
#include <qcstring.h>
#include <qmap.h>
#include <qstringlist.h>
#include <ctype.h>
typedef QMap<QCString, MetaTranslatorMessage> TMM;
typedef QValueList<MetaTranslatorMessage> TML;
static bool isDigitFriendly( int c )
{
- return ispunct( c ) || isspace( c );
+ return ispunct((uchar)c) || isspace((uchar)c);
}
static int numberLength( const char *s )
{
int i = 0;
- if ( isdigit(s[0]) ) {
+ if ( isdigit((uchar)s[0]) ) {
do {
i++;
- } while ( isdigit(s[i]) ||
+ } while (isdigit((uchar)s[i]) ||
(isDigitFriendly(s[i]) &&
- (isdigit(s[i + 1]) ||
- (isDigitFriendly(s[i + 1]) && isdigit(s[i + 2])))) );
+ (isdigit((uchar)s[i + 1]) ||
+ (isDigitFriendly(s[i + 1]) && isdigit((uchar)s[i + 2])))));
}
return i;
}
/*
Returns a version of 'key' where all numbers have been replaced by zeroes. If
there were none, returns "".
*/
static QCString zeroKey( const char *key )
{
QCString zeroed( strlen(key) + 1 );
char *z = zeroed.data();
int i = 0, j = 0;
int len;
bool metSomething = FALSE;
while ( key[i] != '\0' ) {
len = numberLength( key + i );
if ( len > 0 ) {
i += len;
z[j++] = '0';
metSomething = TRUE;
} else {
z[j++] = key[i++];
}
}
z[j] = '\0';
if ( metSomething )
return zeroed;
else
return "";
}
static QString translationAttempt( const QString& oldTranslation,
const char *oldSource,
const char *newSource )
{
int p = zeroKey( oldSource ).contains( '0' );
int oldSourceLen = qstrlen( oldSource );
QString attempt;
QStringList oldNumbers;
QStringList newNumbers;
QMemArray<bool> met( p );
QMemArray<int> matchedYet( p );
int i, j;
int k = 0, ell, best;
int m, n;
@@ -166,70 +172,70 @@ static QString translationAttempt( const QString& oldTranslation,
/*
We flag two kinds of suspicious cases. They are identified as
such with comments such as "{2000?}" at the end.
Example of the first kind: old source text "TeX 3.0" translated
as "XeT 2.0" is flagged "TeX 2.0 {3.0?}", no matter what the
new text is.
*/
for ( k = 0; k < p; k++ ) {
if ( !met[k] )
attempt += QString( " {" ) + newNumbers[k] + QString( "?}" );
}
/*
Example of the second kind: "1 of 1" translated as "1 af 1",
with new source text "1 of 2", generates "1 af 2 {1 or 2?}"
because it's not clear which of "1 af 2" and "2 af 1" is right.
*/
for ( k = 0; k < p; k++ ) {
for ( ell = 0; ell < p; ell++ ) {
if ( k != ell && oldNumbers[k] == oldNumbers[ell] &&
newNumbers[k] < newNumbers[ell] )
attempt += QString( " {" ) + newNumbers[k] + QString( " or " ) +
newNumbers[ell] + QString( "?}" );
}
}
return attempt;
}
/*
Augments a MetaTranslator with translations easily derived from
similar existing (probably obsolete) translations.
For example, if "TeX 3.0" is translated as "XeT 3.0" and "TeX 3.1"
has no translation, "XeT 3.1" is added to the translator and is
marked Unfinished.
*/
void applyNumberHeuristic( MetaTranslator *tor, bool verbose )
{
TMM translated, untranslated;
TMM::Iterator t, u;
TML all = tor->messages();
TML::Iterator it;
int inserted = 0;
for ( it = all.begin(); it != all.end(); ++it ) {
if ( (*it).type() == MetaTranslatorMessage::Unfinished ) {
if ( (*it).translation().isEmpty() )
- untranslated.insert( zeroKey((*it).sourceText()), *it );
+ untranslated.insert(QCString((*it).context()) + "\n" + (*it).sourceText() + "\n"
+ + (*it).comment(), *it);
} else if ( !(*it).translation().isEmpty() ) {
translated.insert( zeroKey((*it).sourceText()), *it );
}
}
for ( u = untranslated.begin(); u != untranslated.end(); ++u ) {
- t = translated.find( u.key() );
+ t = translated.find( zeroKey((*u).sourceText()) );
if ( t != translated.end() && !t.key().isEmpty() &&
qstrcmp((*t).sourceText(), (*u).sourceText()) != 0 ) {
MetaTranslatorMessage m( *u );
- m.setTranslation( translationAttempt((*t).translation(),
- (*t).sourceText(),
+ m.setTranslation(translationAttempt((*t).translation(), (*t).sourceText(),
(*u).sourceText()) );
tor->insert( m );
inserted++;
}
}
if ( verbose && inserted != 0 )
fprintf( stderr, " number heuristic provided %d translation%s\n",
inserted, inserted == 1 ? "" : "s" );
}
diff --git a/development/translation/opie-lupdate/sametexth.cpp b/development/translation/opie-lupdate/sametexth.cpp
index 574cfd5..80909b3 100644
--- a/development/translation/opie-lupdate/sametexth.cpp
+++ b/development/translation/opie-lupdate/sametexth.cpp
@@ -1,62 +1,68 @@
/**********************************************************************
** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
**
** This file is part of Qt Linguist.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include <metatranslator.h>
#include <qcstring.h>
#include <qmap.h>
typedef QMap<QCString, MetaTranslatorMessage> TMM;
typedef QValueList<MetaTranslatorMessage> TML;
/*
Augments a MetaTranslator with trivially derived translations.
For example, if "Enabled:" is consistendly translated as "Eingeschaltet:" no
matter the context or the comment, "Eingeschaltet:" is added as the
translation of any untranslated "Enabled:" text and is marked Unfinished.
*/
void applySameTextHeuristic( MetaTranslator *tor, bool verbose )
{
TMM translated;
TMM avoid;
TMM::Iterator t;
TML untranslated;
TML::Iterator u;
TML all = tor->messages();
TML::Iterator it;
int inserted = 0;
for ( it = all.begin(); it != all.end(); ++it ) {
if ( (*it).type() == MetaTranslatorMessage::Unfinished ) {
if ( (*it).translation().isEmpty() )
untranslated.append( *it );
} else {
QCString key = (*it).sourceText();
t = translated.find( key );
if ( t != translated.end() ) {
/*
The same source text is translated at least two
different ways. Do nothing then.
*/
if ( (*t).translation() != (*it).translation() ) {
translated.remove( key );
avoid.insert( key, *it );
diff --git a/development/translation/shared/metatranslator.cpp b/development/translation/shared/metatranslator.cpp
index a01e1eb..51270c5 100644
--- a/development/translation/shared/metatranslator.cpp
+++ b/development/translation/shared/metatranslator.cpp
@@ -1,62 +1,68 @@
/**********************************************************************
** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
**
** This file is part of Qt Linguist.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include "metatranslator.h"
#include <qapplication.h>
#include <qcstring.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qtextcodec.h>
#include <qtextstream.h>
#include <qxml.h>
static bool encodingIsUtf8( const QXmlAttributes& atts )
{
for ( int i = 0; i < atts.length(); i++ ) {
// utf8="true" is a pre-3.0 syntax
if ( atts.qName(i) == QString("utf8") ) {
return ( atts.value(i) == QString("true") );
} else if ( atts.qName(i) == QString("encoding") ) {
return ( atts.value(i) == QString("UTF-8") );
}
}
return FALSE;
}
class TsHandler : public QXmlDefaultHandler
{
public:
TsHandler( MetaTranslator *translator )
: tor( translator ), type( MetaTranslatorMessage::Finished ),
inMessage( FALSE ), ferrorCount( 0 ), contextIsUtf8( FALSE ),
messageIsUtf8( FALSE ) { }
virtual bool startElement( const QString& namespaceURI,
const QString& localName, const QString& qName,
const QXmlAttributes& atts );
virtual bool endElement( const QString& namespaceURI,
const QString& localName, const QString& qName );
virtual bool characters( const QString& ch );
virtual bool fatalError( const QXmlParseException& exception );
private:
MetaTranslator *tor;
MetaTranslatorMessage::Type type;
@@ -93,101 +99,103 @@ bool TsHandler::startElement( const QString& /* namespaceURI */,
}
} else {
if ( qName == QString("context") ) {
context.truncate( 0 );
source.truncate( 0 );
comment.truncate( 0 );
translation.truncate( 0 );
contextIsUtf8 = encodingIsUtf8( atts );
} else if ( qName == QString("message") ) {
inMessage = TRUE;
type = MetaTranslatorMessage::Finished;
source.truncate( 0 );
comment.truncate( 0 );
translation.truncate( 0 );
messageIsUtf8 = encodingIsUtf8( atts );
} else if ( qName == QString("translation") ) {
for ( int i = 0; i < atts.length(); i++ ) {
if ( atts.qName(i) == QString("type") ) {
if ( atts.value(i) == QString("unfinished") )
type = MetaTranslatorMessage::Unfinished;
else if ( atts.value(i) == QString("obsolete") )
type = MetaTranslatorMessage::Obsolete;
else
type = MetaTranslatorMessage::Finished;
}
}
}
accum.truncate( 0 );
}
return TRUE;
}
bool TsHandler::endElement( const QString& /* namespaceURI */,
const QString& /* localName */,
const QString& qName )
{
if ( qName == QString("codec") || qName == QString("defaultcodec") ) {
// "codec" is a pre-3.0 syntax
tor->setCodec( accum );
} else if ( qName == QString("name") ) {
context = accum;
} else if ( qName == QString("source") ) {
source = accum;
} else if ( qName == QString("comment") ) {
if ( inMessage ) {
comment = accum;
} else {
if ( contextIsUtf8 )
- tor->insert( MetaTranslatorMessage(context.utf8(), "",
+ tor->insert( MetaTranslatorMessage(context.utf8(),
+ ContextComment,
accum.utf8(), QString::null, TRUE,
MetaTranslatorMessage::Unfinished) );
else
- tor->insert( MetaTranslatorMessage(context.ascii(), "",
+ tor->insert( MetaTranslatorMessage(context.ascii(),
+ ContextComment,
accum.ascii(), QString::null, FALSE,
MetaTranslatorMessage::Unfinished) );
}
} else if ( qName == QString("translation") ) {
translation = accum;
} else if ( qName == QString("message") ) {
if ( messageIsUtf8 )
tor->insert( MetaTranslatorMessage(context.utf8(), source.utf8(),
comment.utf8(), translation,
TRUE, type) );
else
tor->insert( MetaTranslatorMessage(context.ascii(), source.ascii(),
comment.ascii(), translation,
FALSE, type) );
inMessage = FALSE;
}
return TRUE;
}
bool TsHandler::characters( const QString& ch )
{
QString t = ch;
t.replace( "\r", "" );
accum += t;
return TRUE;
}
bool TsHandler::fatalError( const QXmlParseException& exception )
{
if ( ferrorCount++ == 0 ) {
QString msg;
msg.sprintf( "Parse error at line %d, column %d (%s).",
exception.lineNumber(), exception.columnNumber(),
exception.message().latin1() );
if ( qApp == 0 )
fprintf( stderr, "XML error: %s\n", msg.latin1() );
else
QMessageBox::information( qApp->mainWidget(),
QObject::tr("Qt Linguist"), msg );
}
return FALSE;
}
static QString numericEntity( int ch )
{
return QString( ch <= 0x20 ? "<byte value=\"x%1\"/>" : "&#x%1;" )
.arg( ch, 0, 16 );
}
@@ -270,305 +278,307 @@ MetaTranslatorMessage::MetaTranslatorMessage( const char *context,
i++;
}
}
if ( !utfeight && comment != 0 ) {
int i = 0;
while ( comment[i] != '\0' ) {
if ( (uchar) comment[i] >= 0x80 ) {
utfeight = TRUE;
break;
}
i++;
}
}
}
}
MetaTranslatorMessage::MetaTranslatorMessage( const MetaTranslatorMessage& m )
: QTranslatorMessage( m ), utfeight( m.utfeight ), ty( m.ty )
{
}
MetaTranslatorMessage& MetaTranslatorMessage::operator=(
const MetaTranslatorMessage& m )
{
QTranslatorMessage::operator=( m );
utfeight = m.utfeight;
ty = m.ty;
return *this;
}
bool MetaTranslatorMessage::operator==( const MetaTranslatorMessage& m ) const
{
return qstrcmp( context(), m.context() ) == 0 &&
qstrcmp( sourceText(), m.sourceText() ) == 0 &&
qstrcmp( comment(), m.comment() ) == 0;
}
bool MetaTranslatorMessage::operator<( const MetaTranslatorMessage& m ) const
{
int delta = qstrcmp( context(), m.context() );
if ( delta == 0 )
delta = qstrcmp( sourceText(), m.sourceText() );
if ( delta == 0 )
delta = qstrcmp( comment(), m.comment() );
return delta < 0;
}
MetaTranslator::MetaTranslator()
- : codecName( "ISO-8859-1" ), codec( 0 )
{
+ clear();
}
MetaTranslator::MetaTranslator( const MetaTranslator& tor )
: mm( tor.mm ), codecName( tor.codecName ), codec( tor.codec )
{
-
}
MetaTranslator& MetaTranslator::operator=( const MetaTranslator& tor )
{
mm = tor.mm;
codecName = tor.codecName;
codec = tor.codec;
return *this;
}
-bool MetaTranslator::load( const QString& filename )
+void MetaTranslator::clear()
{
mm.clear();
+ codecName = "ISO-8859-1";
+ codec = 0;
+}
+bool MetaTranslator::load( const QString& filename )
+{
QFile f( filename );
if ( !f.open(IO_ReadOnly) )
return FALSE;
QTextStream t( &f );
QXmlInputSource in( t );
QXmlSimpleReader reader;
- // don't click on these!
reader.setFeature( "http://xml.org/sax/features/namespaces", FALSE );
reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", TRUE );
reader.setFeature( "http://trolltech.com/xml/features/report-whitespace"
"-only-CharData", FALSE );
QXmlDefaultHandler *hand = new TsHandler( this );
reader.setContentHandler( hand );
reader.setErrorHandler( hand );
bool ok = reader.parse( in );
reader.setContentHandler( 0 );
reader.setErrorHandler( 0 );
delete hand;
f.close();
- if ( !ok )
- mm.clear();
return ok;
}
bool MetaTranslator::save( const QString& filename ) const
{
QFile f( filename );
if ( !f.open(IO_WriteOnly) )
return FALSE;
QTextStream t( &f );
t.setCodec( QTextCodec::codecForName("ISO-8859-1") );
t << "<!DOCTYPE TS><TS>\n";
if ( codecName != "ISO-8859-1" )
t << "<defaultcodec>" << codecName << "</defaultcodec>\n";
TMM::ConstIterator m = mm.begin();
while ( m != mm.end() ) {
TMMInv inv;
TMMInv::Iterator i;
bool contextIsUtf8 = m.key().utf8();
QCString context = m.key().context();
QCString comment = "";
do {
- if ( QCString(m.key().sourceText()).isEmpty() ) {
+ if ( QCString(m.key().sourceText()) == ContextComment ) {
if ( m.key().type() != MetaTranslatorMessage::Obsolete ) {
contextIsUtf8 = m.key().utf8();
comment = QCString( m.key().comment() );
}
} else {
inv.insert( *m, m.key() );
}
} while ( ++m != mm.end() && QCString(m.key().context()) == context );
t << "<context";
if ( contextIsUtf8 )
t << " encoding=\"UTF-8\"";
t << ">\n";
t << " <name>" << evilBytes( context, contextIsUtf8 )
<< "</name>\n";
if ( !comment.isEmpty() )
t << " <comment>" << evilBytes( comment, contextIsUtf8 )
<< "</comment>\n";
for ( i = inv.begin(); i != inv.end(); ++i ) {
// no need for such noise
if ( (*i).type() == MetaTranslatorMessage::Obsolete &&
(*i).translation().isEmpty() )
continue;
t << " <message";
if ( (*i).utf8() )
t << " encoding=\"UTF-8\"";
t << ">\n"
<< " <source>" << evilBytes( (*i).sourceText(),
(*i).utf8() )
<< "</source>\n";
if ( !QCString((*i).comment()).isEmpty() )
t << " <comment>" << evilBytes( (*i).comment(),
(*i).utf8() )
<< "</comment>\n";
t << " <translation";
if ( (*i).type() == MetaTranslatorMessage::Unfinished )
t << " type=\"unfinished\"";
else if ( (*i).type() == MetaTranslatorMessage::Obsolete )
t << " type=\"obsolete\"";
t << ">" << protect( (*i).translation().utf8() )
<< "</translation>\n";
t << " </message>\n";
}
t << "</context>\n";
}
t << "</TS>\n";
f.close();
return TRUE;
}
-bool MetaTranslator::release( const QString& filename, bool verbose ) const
+bool MetaTranslator::release( const QString& filename, bool verbose,
+ QTranslator::SaveMode mode ) const
{
QTranslator tor( 0 );
int finished = 0;
int unfinished = 0;
int untranslated = 0;
TMM::ConstIterator m;
for ( m = mm.begin(); m != mm.end(); ++m ) {
if ( m.key().type() != MetaTranslatorMessage::Obsolete ) {
if ( m.key().translation().isEmpty() ) {
untranslated++;
} else {
if ( m.key().type() == MetaTranslatorMessage::Unfinished )
unfinished++;
else
finished++;
QCString context = m.key().context();
QCString sourceText = m.key().sourceText();
QCString comment = m.key().comment();
QString translation = m.key().translation();
/*
Drop the comment in (context, sourceText, comment),
unless (context, sourceText, "") already exists, or
unless we already dropped the comment of (context,
sourceText, comment0).
*/
if ( comment.isEmpty()
|| contains(context, sourceText, "")
|| !tor.findMessage(context, sourceText, "").translation()
.isNull() ) {
tor.insert( m.key() );
} else {
tor.insert( QTranslatorMessage(context, sourceText, "",
translation) );
}
}
}
}
- bool saved = tor.save( filename, QTranslator::Stripped );
+ bool saved = tor.save( filename, mode );
if ( saved && verbose )
fprintf( stderr,
" %d finished, %d unfinished and %d untranslated messages\n",
finished, unfinished, untranslated );
return saved;
}
bool MetaTranslator::contains( const char *context, const char *sourceText,
const char *comment ) const
{
return mm.find( MetaTranslatorMessage(context, sourceText, comment) ) !=
mm.end();
}
void MetaTranslator::insert( const MetaTranslatorMessage& m )
{
int pos = mm.count();
TMM::Iterator n = mm.find( m );
if ( n != mm.end() )
pos = *n;
mm.replace( m, pos );
}
void MetaTranslator::stripObsoleteMessages()
{
TMM newmm;
TMM::Iterator m = mm.begin();
while ( m != mm.end() ) {
if ( m.key().type() != MetaTranslatorMessage::Obsolete )
newmm.insert( m.key(), *m );
++m;
}
mm = newmm;
}
void MetaTranslator::stripEmptyContexts()
{
TMM newmm;
TMM::Iterator m = mm.begin();
while ( m != mm.end() ) {
- if ( QCString(m.key().sourceText()).isEmpty() ) {
+ if ( QCString(m.key().sourceText()) == ContextComment ) {
TMM::Iterator n = m;
++n;
// the context comment is followed by other messages
if ( n != newmm.end() &&
qstrcmp(m.key().context(), n.key().context()) == 0 )
newmm.insert( m.key(), *m );
} else {
newmm.insert( m.key(), *m );
}
++m;
}
mm = newmm;
}
void MetaTranslator::setCodec( const char *name )
{
const int latin1 = 4;
codecName = name;
codec = QTextCodec::codecForName( name );
if ( codec == 0 || codec->mibEnum() == latin1 )
codec = 0;
}
QString MetaTranslator::toUnicode( const char *str, bool utf8 ) const
{
if ( utf8 )
return QString::fromUtf8( str );
else if ( codec == 0 )
return QString( str );
else
return codec->toUnicode( str );
}
QValueList<MetaTranslatorMessage> MetaTranslator::messages() const
{
int n = mm.count();
TMM::ConstIterator *t = new TMM::ConstIterator[n + 1];
TMM::ConstIterator m;
for ( m = mm.begin(); m != mm.end(); ++m )
t[*m] = m;
QValueList<MetaTranslatorMessage> val;
for ( int i = 0; i < n; i++ )
val.append( t[i].key() );
delete[] t;
return val;
diff --git a/development/translation/shared/metatranslator.h b/development/translation/shared/metatranslator.h
index d35b202..a13f462 100644
--- a/development/translation/shared/metatranslator.h
+++ b/development/translation/shared/metatranslator.h
@@ -1,99 +1,113 @@
/**********************************************************************
** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
**
** This file is part of Qt Linguist.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#ifndef METATRANSLATOR_H
#define METATRANSLATOR_H
#include <qmap.h>
#include <qstring.h>
#include <qtranslator.h>
#include <qvaluelist.h>
class QTextCodec;
class MetaTranslatorMessage : public QTranslatorMessage
{
public:
enum Type { Unfinished, Finished, Obsolete };
MetaTranslatorMessage();
MetaTranslatorMessage( const char *context, const char *sourceText,
const char *comment,
const QString& translation = QString::null,
bool utf8 = FALSE, Type type = Unfinished );
MetaTranslatorMessage( const MetaTranslatorMessage& m );
MetaTranslatorMessage& operator=( const MetaTranslatorMessage& m );
void setType( Type nt ) { ty = nt; }
Type type() const { return ty; }
bool utf8() const { return utfeight; }
bool operator==( const MetaTranslatorMessage& m ) const;
bool operator!=( const MetaTranslatorMessage& m ) const
{ return !operator==( m ); }
bool operator<( const MetaTranslatorMessage& m ) const;
bool operator<=( const MetaTranslatorMessage& m )
{ return !operator>( m ); }
bool operator>( const MetaTranslatorMessage& m ) const
{ return this->operator<( m ); }
bool operator>=( const MetaTranslatorMessage& m ) const
{ return !operator<( m ); }
private:
bool utfeight;
Type ty;
};
class MetaTranslator
{
public:
MetaTranslator();
MetaTranslator( const MetaTranslator& tor );
MetaTranslator& operator=( const MetaTranslator& tor );
+ void clear();
bool load( const QString& filename );
bool save( const QString& filename ) const;
- bool release( const QString& filename, bool verbose = FALSE ) const;
+ bool release( const QString& filename, bool verbose = FALSE,
+ QTranslator::SaveMode mode = QTranslator::Stripped ) const;
bool contains( const char *context, const char *sourceText,
const char *comment ) const;
void insert( const MetaTranslatorMessage& m );
void stripObsoleteMessages();
void stripEmptyContexts();
void setCodec( const char *name );
QString toUnicode( const char *str, bool utf8 ) const;
QValueList<MetaTranslatorMessage> messages() const;
QValueList<MetaTranslatorMessage> translatedMessages() const;
private:
typedef QMap<MetaTranslatorMessage, int> TMM;
typedef QMap<int, MetaTranslatorMessage> TMMInv;
TMM mm;
QCString codecName;
QTextCodec *codec;
};
+/*
+ This is a quick hack. The proper way to handle this would be
+ to extend MetaTranslator's interface.
+*/
+#define ContextComment "QT_LINGUIST_INTERNAL_CONTEXT_COMMENT"
+
#endif
diff --git a/development/translation/shared/opie.h b/development/translation/shared/opie.h
index 4646bb0..28b2a61 100644
--- a/development/translation/shared/opie.h
+++ b/development/translation/shared/opie.h
@@ -1,21 +1,21 @@
#ifndef OPIE_H
#define OPIE_H
#include <qstring.h>
#include <qstringlist.h>
class OPIE {
public:
static OPIE* self();
/** get the list of languages */
QStringList languageList(const QString& opiedir = QString::null)const;
- QString opieDir(const QString& opieDir)const;
+ QString opieDir(const QString& opieDir = QString::null)const;
private:
OPIE();
~OPIE();
static OPIE* m_self;
};
#endif
diff --git a/development/translation/shared/proparser.cpp b/development/translation/shared/proparser.cpp
index 21d2f86..f616c5a 100644
--- a/development/translation/shared/proparser.cpp
+++ b/development/translation/shared/proparser.cpp
@@ -1,87 +1,174 @@
/**********************************************************************
** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
**
** This file is part of Qt Linguist.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include "proparser.h"
+#include <qfile.h>
#include <qregexp.h>
#include <qstringlist.h>
+#include <qtextstream.h>
+
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#endif
+
+#ifdef Q_OS_WIN32
+#define QT_POPEN _popen
+#else
+#define QT_POPEN popen
+#endif
-QMap<QString, QString> proFileTagMap( const QString& text )
+QString loadFile( const QString &fileName )
+{
+ QFile file( fileName );
+ if ( !file.open(IO_ReadOnly) ) {
+ fprintf( stderr, "error: Cannot load '%s': %s\n",
+ file.name().latin1(),
+ file.errorString().latin1() );
+ return QString();
+ }
+
+ QTextStream in( &file );
+ return in.read();
+}
+
+QMap<QString, QString> proFileTagMap( const QString& text, const QString& opieDir )
{
QString t = text;
/*
+ Process include() commands.
+ */
+ QRegExp callToInclude("include\\s*\\(\\s*([^()\\s]+)\\s*\\)");
+ int i = 0;
+ while ( (i = callToInclude.search(t, i)) != -1 ) {
+ QString after = loadFile( callToInclude.cap(1) );
+ t.replace( i, callToInclude.matchedLength(), after );
+ i += after.length();
+ }
+
+ /*
Strip comments, merge lines ending with backslash, add
spaces around '=' and '+=', replace '\n' with ';', and
simplify white spaces.
*/
- t.replace( QRegExp(QString("#[^\n]$")), QString(" ") );
- t.replace( QRegExp(QString("\\\\\\s*\n")), QString(" ") );
+ t.replace( QRegExp(QString("#[^\n]*\n")), QString(" ") );
+ t.replace( QRegExp(QString("\\\\[^\n\\S]*\n")), QString(" ") );
t.replace( "=", QString(" = ") );
t.replace( "+ =", QString(" += ") );
t.replace( "\n", QString(";") );
t = t.simplifyWhiteSpace();
+ /*
+ Populate tagMap with 'key = value' entries.
+ */
QMap<QString, QString> tagMap;
-
QStringList lines = QStringList::split( QChar(';'), t );
QStringList::Iterator line;
for ( line = lines.begin(); line != lines.end(); ++line ) {
QStringList toks = QStringList::split( QChar(' '), *line );
if ( toks.count() >= 3 &&
(toks[1] == QString("=") || toks[1] == QString("+=")) ) {
QString tag = toks.first();
int k = tag.findRev( QChar(':') ); // as in 'unix:'
if ( k != -1 )
tag = tag.mid( k + 1 );
toks.remove( toks.begin() );
QString action = toks.first();
toks.remove( toks.begin() );
if ( tagMap.contains(tag) ) {
if ( action == QString("=") )
tagMap.replace( tag, toks.join(QChar(' ')) );
else
tagMap[tag] += QChar( ' ' ) + toks.join( QChar(' ') );
} else {
tagMap[tag] = toks.join( QChar(' ') );
}
}
}
- QRegExp var( "\\$\\$[a-zA-Z0-9_]+" );
+ /*
+ Expand $$variables within the 'value' part of a 'key = value'
+ pair.
+ */
+ QRegExp var( "\\$\\$[({]?([a-zA-Z0-9_]+)[)}]?" );
QMap<QString, QString>::Iterator it;
for ( it = tagMap.begin(); it != tagMap.end(); ++it ) {
int i = 0;
-
- while ( (i = var.search(it.data(), i)) != -1 ) {
+ while ( (i = var.search((*it), i)) != -1 ) {
int len = var.matchedLength();
- QString invocation = (*it).mid( i + 2, len - 2 );
+ QString invocation = var.cap(1);
QString after;
+
+ if ( invocation == "system" ) {
+ // skip system(); it will be handled in the next pass
+ ++i;
+ } else if ( invocation == "OPIEDIR") {
+ (*it).replace( i, len, opieDir );
+ }else {
if ( tagMap.contains(invocation) )
after = tagMap[invocation];
(*it).replace( i, len, after );
+ }
+ }
+ }
+
+ /*
+ Execute system() calls.
+ */
+ QRegExp callToSystem( "\\$\\$system\\s*\\(([^()]*)\\)" );
+ for ( it = tagMap.begin(); it != tagMap.end(); ++it ) {
+ int i = 0;
+ while ( (i = callToSystem.search((*it), i)) != -1 ) {
+ /*
+ This code is stolen from qmake's project.cpp file.
+ Ideally we would use the same parser, so we wouldn't
+ have this code duplication.
+ */
+ QString after;
+ char buff[256];
+ FILE *proc = QT_POPEN( callToSystem.cap(1).latin1(), "r" );
+ while ( proc && !feof(proc) ) {
+ int read_in = fread( buff, 1, 255, proc );
+ if ( !read_in )
+ break;
+ for ( int i = 0; i < read_in; i++ ) {
+ if ( buff[i] == '\n' || buff[i] == '\t' )
+ buff[i] = ' ';
+ }
+ buff[read_in] = '\0';
+ after += buff;
+ }
+ (*it).replace( i, callToSystem.matchedLength(), after );
i += after.length();
}
}
+
return tagMap;
}
diff --git a/development/translation/shared/proparser.h b/development/translation/shared/proparser.h
index 6a61d90..e5678d6 100644
--- a/development/translation/shared/proparser.h
+++ b/development/translation/shared/proparser.h
@@ -1,29 +1,35 @@
/**********************************************************************
** Copyright (C) 2000 Trolltech AS. All rights reserved.
**
** This file is part of Qt Linguist.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#ifndef PROPARSER_H
#define PROPARSER_H
#include <qmap.h>
#include <qstring.h>
-QMap<QString, QString> proFileTagMap( const QString& text );
+QMap<QString, QString> proFileTagMap( const QString& text, const QString& = QString::null );
#endif