[ Index ] |
|
Code source de eZ Publish 3.9.0 |
1 /********************************************************************** 2 ** Copyright (C) 2000 Trolltech AS. All rights reserved. 3 ** 4 ** numberh.cpp 5 ** 6 ** This file is part of Qt Linguist. 7 ** 8 ** See the file LICENSE included in the distribution for the usage 9 ** and distribution terms. 10 ** 11 ** The file is provided AS IS with NO WARRANTY OF ANY KIND, 12 ** INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR 13 ** A PARTICULAR PURPOSE. 14 ** 15 **********************************************************************/ 16 17 #include <qmemarray.h> 18 #include <qcstring.h> 19 #include <qmap.h> 20 #include <qstringlist.h> 21 22 #include <ctype.h> 23 #include <metatranslator.h> 24 25 typedef QMap<QCString, MetaTranslatorMessage> TMM; 26 typedef QValueList<MetaTranslatorMessage> TML; 27 28 static bool isDigitFriendly( int c ) 29 { 30 return ispunct( c ) || isspace( c ); 31 } 32 33 static int numberLength( const char *s ) 34 { 35 int i = 0; 36 37 if ( isdigit(s[0]) ) { 38 do { 39 i++; 40 } while ( isdigit(s[i]) || 41 (isDigitFriendly(s[i]) && 42 (isdigit(s[i + 1]) || 43 (isDigitFriendly(s[i + 1]) && isdigit(s[i + 2])))) ); 44 } 45 return i; 46 } 47 48 /* 49 Returns a version of 'key' where all numbers have been replaced by zeroes. If 50 there were none, returns "". 51 */ 52 static QCString zeroKey( const char *key ) 53 { 54 QCString zeroed( strlen(key) + 1 ); 55 char *z = zeroed.data(); 56 int i = 0, j = 0; 57 int len; 58 bool metSomething = FALSE; 59 60 while ( key[i] != '\0' ) { 61 len = numberLength( key + i ); 62 if ( len > 0 ) { 63 i += len; 64 z[j++] = '0'; 65 metSomething = TRUE; 66 } else { 67 z[j++] = key[i++]; 68 } 69 } 70 z[j] = '\0'; 71 72 if ( metSomething ) 73 return zeroed; 74 else 75 return ""; 76 } 77 78 static QString translationAttempt( const QString& oldTranslation, 79 const char *oldSource, 80 const char *newSource ) 81 { 82 int p = zeroKey( oldSource ).contains( '0' ); 83 int oldSourceLen = qstrlen( oldSource ); 84 QString attempt; 85 QStringList oldNumbers; 86 QStringList newNumbers; 87 QMemArray<bool> met( p ); 88 QMemArray<int> matchedYet( p ); 89 int i, j; 90 int k = 0, ell, best; 91 int m, n; 92 int pass; 93 94 /* 95 This algorithm is hard to follow, so we'll consider an example 96 all along: oldTranslation is "XeT 3.0", oldSource is "TeX 3.0" 97 and newSource is "XeT 3.1". 98 99 First, we set up two tables: oldNumbers and newNumbers. In our 100 example, oldNumber[0] is "3.0" and newNumber[0] is "3.1". 101 */ 102 for ( i = 0, j = 0; i < oldSourceLen; i++, j++ ) { 103 m = numberLength( oldSource + i ); 104 n = numberLength( newSource + j ); 105 if ( m > 0 ) { 106 oldNumbers.append( QCString(oldSource + i, m + 1) ); 107 newNumbers.append( QCString(newSource + j, n + 1) ); 108 i += m; 109 j += n; 110 met[k] = FALSE; 111 matchedYet[k] = 0; 112 k++; 113 } 114 } 115 116 /* 117 We now go over the old translation, "XeT 3.0", one letter at a 118 time, looking for numbers found in oldNumbers. Whenever such a 119 number is met, it is replaced with its newNumber equivalent. In 120 our example, the "3.0" of "XeT 3.0" becomes "3.1". 121 */ 122 for ( i = 0; i < (int) oldTranslation.length(); i++ ) { 123 attempt += oldTranslation[i]; 124 for ( k = 0; k < p; k++ ) { 125 if ( oldTranslation[i] == oldNumbers[k][matchedYet[k]] ) 126 matchedYet[k]++; 127 else 128 matchedYet[k] = 0; 129 } 130 131 /* 132 Let's find out if the last character ended a match. We make 133 two passes over the data. In the first pass, we try to 134 match only numbers that weren't matched yet; if that fails, 135 the second pass does the trick. This is useful in some 136 suspicious cases, flagged below. 137 */ 138 for ( pass = 0; pass < 2; pass++ ) { 139 best = p; // an impossible value 140 for ( k = 0; k < p; k++ ) { 141 if ( (!met[k] || pass > 0) && 142 matchedYet[k] == (int) oldNumbers[k].length() && 143 numberLength(oldTranslation.latin1() + (i + 1) - 144 matchedYet[k]) == matchedYet[k] ) { 145 // the longer the better 146 if ( best == p || matchedYet[k] > matchedYet[best] ) 147 best = k; 148 } 149 } 150 if ( best != p ) { 151 attempt.truncate( attempt.length() - matchedYet[best] ); 152 attempt += newNumbers[best]; 153 met[best] = TRUE; 154 for ( k = 0; k < p; k++ ) 155 matchedYet[k] = 0; 156 break; 157 } 158 } 159 } 160 161 /* 162 We flag two kinds of suspicious cases. They are identified as 163 such with comments such as "{2000?}" at the end. 164 165 Example of the first kind: old source text "TeX 3.0" translated 166 as "XeT 2.0" is flagged "TeX 2.0 {3.0?}", no matter what the 167 new text is. 168 */ 169 for ( k = 0; k < p; k++ ) { 170 if ( !met[k] ) 171 attempt += QString( " {" ) + newNumbers[k] + QString( "?}" ); 172 } 173 174 /* 175 Example of the second kind: "1 of 1" translated as "1 af 1", 176 with new source text "1 of 2", generates "1 af 2 {1 or 2?}" 177 because it's not clear which of "1 af 2" and "2 af 1" is right. 178 */ 179 for ( k = 0; k < p; k++ ) { 180 for ( ell = 0; ell < p; ell++ ) { 181 if ( k != ell && oldNumbers[k] == oldNumbers[ell] && 182 newNumbers[k] < newNumbers[ell] ) 183 attempt += QString( " {" ) + newNumbers[k] + QString( " or " ) + 184 newNumbers[ell] + QString( "?}" ); 185 } 186 } 187 return attempt; 188 } 189 190 /* 191 Augments a MetaTranslator with translations easily derived from 192 similar existing (probably obsolete) translations. 193 194 For example, if "TeX 3.0" is translated as "XeT 3.0" and "TeX 3.1" 195 has no translation, "XeT 3.1" is added to the translator and is 196 marked Unfinished. 197 */ 198 void applyNumberHeuristic( MetaTranslator *tor, bool verbose ) 199 { 200 TMM translated, untranslated; 201 TMM::Iterator t, u; 202 TML all = tor->messages(); 203 TML::Iterator it; 204 int inserted = 0; 205 206 for ( it = all.begin(); it != all.end(); ++it ) { 207 if ( (*it).type() == MetaTranslatorMessage::Unfinished ) { 208 if ( (*it).translation().isEmpty() ) 209 untranslated.insert( zeroKey((*it).sourceText()), *it ); 210 } else if ( !(*it).translation().isEmpty() ) { 211 translated.insert( zeroKey((*it).sourceText()), *it ); 212 } 213 } 214 215 for ( u = untranslated.begin(); u != untranslated.end(); ++u ) { 216 t = translated.find( u.key() ); 217 if ( t != translated.end() && !t.key().isEmpty() && 218 qstrcmp((*t).sourceText(), (*u).sourceText()) != 0 ) { 219 MetaTranslatorMessage m( *u ); 220 m.setTranslation( translationAttempt((*t).translation(), 221 (*t).sourceText(), 222 (*u).sourceText()) ); 223 tor->insert( m ); 224 inserted++; 225 } 226 } 227 if ( verbose && inserted != 0 ) 228 qWarning( " number heuristic provided %d translation%s", 229 inserted, inserted == 1 ? "" : "s" ); 230 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sat Feb 24 10:30:04 2007 | par Balluche grâce à PHPXref 0.7 |