![]() |
Xataface Translation Memory Module 0.1
Translation Memory for Xataface Applications
|
00001 <?php 00002 /* 00003 * Xataface Translation Memory Module 00004 * Copyright (C) 2011 Steve Hannah <steve@weblite.ca> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Library General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Library General Public 00017 * License along with this library; if not, write to the 00018 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 * 00021 */ 00022 require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'TMTools.php'); 00023 00028 class XFTranslationMemory { 00029 00030 const TRANSLATION_REJECTED=1; 00031 //const TRANSLATION_VOTE_DOWN=2; 00032 const TRANSLATION_SUBMITTED=3; 00033 //const TRANSLATION_VOTE_UP=4; 00034 const TRANSLATION_APPROVED=5; 00035 00041 private $_rec; 00042 00043 00049 public function __construct(Dataface_Record $rec){ 00050 $this->_rec = $rec; 00051 } 00052 00057 public function getRecord(){ 00058 return $this->_rec; 00059 } 00060 00065 public function getSourceLanguage(){ 00066 return $this->_rec->val('source_language'); 00067 } 00068 00069 00074 public function getDestinationLanguage(){ 00075 return $this->_rec->val('destination_language'); 00076 } 00077 00078 00084 private static $defaultTranslationMemories = null; 00085 00086 00098 public static function getDefaultTranslationMemory($source, $dest, $secure=false){ 00099 $source = strtolower($source); 00100 $dest = strtolower($dest); 00101 if ( !isset(self::$defaultTranslationMemories) ){ 00102 self::$defaultTranslationMemories = array(); 00103 } 00104 00105 if ( !isset(self::$defaultTranslationMemories[$source]) ){ 00106 self::$defaultTranslationMemories[$source] = array(); 00107 } 00108 00109 if ( !isset(self::$defaultTranslationMemories[$source][$dest]) ){ 00110 $rec = df_get_record('xf_tm_records', 00111 array( 00112 'record_id'=>'=*', 00113 'source_language'=>'='.$source, 00114 'destination_language'=>'='.$dest 00115 ) 00116 ); 00117 00118 if ( $rec ){ 00119 00120 self::$defaultTranslationMemories[$source][$dest] = self::loadTranslationMemoryById($rec->val('translation_memory_id')); 00121 00122 } 00123 } 00124 00125 if ( !isset(self::$defaultTranslationMemories[$source][$dest]) ){ 00126 $tm = self::createTranslationMemory('Default '.$source.'=>'.$dest, $source, $dest, $secure); 00127 $tm->assignTo('*'); 00128 self::$defaultTranslationMemories[$source][$dest] = $tm; 00129 } 00130 return self::$defaultTranslationMemories[$source][$dest]; 00131 } 00132 00148 private static function createTranslationMemory($name, $source, $dest, $secure=false){ 00149 $source = strtolower($source); $dest = strtolower($dest); 00150 if ( !preg_match('/^[a-z0-9]{2}$/', $source) ){ 00151 throw new Exception("Invalid source language code inserting a translation memory: $source"); 00152 } 00153 if ( !preg_match('/^[a-z0-9]{2}$/', $dest) ){ 00154 throw new Exception("Invalid destination language code inserting a translation memory: $dest"); 00155 } 00156 00157 $rec = new Dataface_Record('xf_tm_translation_memories',array()); 00158 $rec->setValues(array( 00159 'translation_memory_name'=>$name, 00160 'source_language'=>$source, 00161 'destination_language'=>$dest 00162 )); 00163 $res = $rec->save($secure); 00164 if ( PEAR::isError($res) ){ 00165 throw new Exception("Failed to create translation memory ".$res->getMessage(), $res->getCode()); 00166 } 00167 00168 $tm = new XFTranslationMemory($rec); 00169 00170 return $tm; 00171 } 00172 00173 00174 00184 public function assignTo($recid, $secure = false){ 00185 $rec = new Dataface_Record('xf_tm_records', array()); 00186 $rec->setValues(array( 00187 'record_id'=>$recid, 00188 'translation_memory_id'=>$this->_rec->val('translation_memory_id') 00189 )); 00190 $res = $rec->save($secure); 00191 if ( PEAR::isError($res) ){ 00192 throw new Exception("Failed to assign the translation memory to the record with id ".$recid); 00193 00194 } 00195 00196 } 00197 00203 public static function loadTranslationMemoryById($id){ 00204 $tmrec = df_get_record('xf_tm_translation_memories', array('translation_memory_id'=>'='.$id)); 00205 if ( !$tmrec ) return null; 00206 return new XFTranslationMemory($tmrec); 00207 } 00208 00209 00218 public static function loadTranslationMemoryFor(Dataface_Record $record, $source, $dest){ 00219 $rec = df_get_record('xf_tm_records', 00220 array( 00221 'record_id'=>'='.$record->getId(), 00222 'source_language'=>'='.$source, 00223 'destination_language'=>'='.$dest 00224 ) 00225 ); 00226 if ( !$rec ){ 00227 return self::getDefaultTranslationMemory($source, $dest); 00228 } 00229 00230 if ( !$rec->val('translation_memory_id') ){ 00231 return null; 00232 } 00233 00234 return self::loadTranslationMemoryById($rec->val('translation_memory_id')); 00235 } 00236 00250 public function addTranslation($string, $translation, $username=null, $secure=false){ 00251 if ( !$username ) $username = Dataface_AuthenticationTool::getInstance()->getLoggedInUserName(); 00252 $strid = null; 00253 if ( is_int($string) ){ 00254 $strid = $string; 00255 } 00256 00257 if ( !$strid ){ 00258 $strRec = self::findString($string, $this->getSourceLanguage()); 00259 if ( !$strRec ){ 00260 $strRec = self::addString($string, $this->getSourceLanguage(), $secure); 00261 00262 } 00263 if ( !$strRec ){ 00264 throw new Exception("Failed to add string $string"); 00265 } 00266 $strid = intval($strRec->val('string_id')); 00267 00268 } 00269 00270 00271 $trec = $this->findTranslation($strid, $translation); 00272 if ( !$trec ){ 00273 00274 $normalized = TMTools::normalize($translation); 00275 $hash = md5($normalized); 00276 $trec = new Dataface_Record('xf_tm_translations', array()); 00277 $trec->setValues(array( 00278 'string_id'=>$strid, 00279 'translation_value'=>$translation, 00280 'normalized_translation_value'=> $normalized, 00281 'language'=> $this->getDestinationLanguage(), 00282 'translation_hash'=>$hash, 00283 'created_by' => $username 00284 )); 00285 $res = $trec->save($secure); 00286 if ( PEAR::isError($res) ){ 00287 throw new Exception('Failed to add translation "$translation": '.$res->getMessage(), $res->getCode()); 00288 } 00289 } 00290 00291 // Now add this translation to the translation memory 00292 $res = mysql_query("insert ignore into xf_tm_translation_memory_translations 00293 (translation_memory_id,translation_id) 00294 values 00295 ('".addslashes($this->_rec->val('translation_memory_id'))."', 00296 '".addslashes($trec->val('translation_id'))."' 00297 )", df_db()); 00298 if ( !$res ) throw new Exception(mysql_error(df_db())); 00299 00300 00301 return $trec; 00302 00303 00304 00305 00306 } 00307 00315 public function containsTranslation($string, $translation){ 00316 $tr = $this->findTranslation($string, $translation); 00317 if ( !$tr ) return false; 00318 $tm = df_get_record('xf_tm_translation_memory_translations', 00319 array( 00320 'translation_memory_id'=>'='.$this->_rec->val('translation_memory_id'), 00321 'translation_id'=>'='.$tr->val('translation_id') 00322 ) 00323 ); 00324 if ( !$tm ) return false; 00325 else return true; 00326 } 00327 00328 00334 public static function findString($string, $language){ 00335 $normalized = TMTools::normalize($string); 00336 $hash = md5($normalized); 00337 $strRec = df_get_record('xf_tm_strings', 00338 array( 00339 'normalized_value'=>'='.$normalized, 00340 'hash'=>'='.$hash, 00341 'language'=>'='.$language)); 00342 if ( !$strRec ) return null; 00343 return $strRec; 00344 } 00345 00346 00355 public static function addString($string, $language, $secure=false){ 00356 00357 $str = self::findString($string, $language); 00358 if ( !$str ){ 00359 $app = Dataface_Application::getInstance(); 00360 $strRec = new Dataface_Record('xf_tm_strings', array()); 00361 $normalized = TMTools::normalize($string); 00362 $hash = md5($normalized); 00363 $strRec->setValues(array( 00364 'language'=>$language, 00365 'string_value'=>$string, 00366 'normalized_value'=>$normalized, 00367 'hash'=> $hash 00368 )); 00369 $res = $strRec->save($secure); 00370 if ( PEAR::isError($res) ){ 00371 00372 throw new Exception($res->getMessage()); 00373 } 00374 return $strRec; 00375 00376 } 00377 return $str; 00378 } 00379 00380 00389 public function findTranslation($string, $translation){ 00390 $strid = null; 00391 if ( is_int($string) ) $strid = $string; 00392 00393 if ( !$strid ){ 00394 00395 $strRec = self::findString($string, $this->getSourceLanguage()); 00396 if ( $strRec ){ 00397 $strid = intval($strRec->val('string_id')); 00398 } 00399 00400 } 00401 if ( !$strid ) return null; 00402 00403 $normalizedTranslation = TMTools::normalize($translation); 00404 $hashTranslation = md5($normalizedTranslation); 00405 00406 $trRec = df_get_record('xf_tm_translations', 00407 array( 00408 'string_id'=>'='.$strid, 00409 'normalized_translation_value'=>'='.$normalizedTranslation, 00410 'translation_hash'=>'='.$hashTranslation, 00411 'language'=>'='.$this->getDestinationLanguage() 00412 00413 ) 00414 ); 00415 00416 if ( !$trRec ) return null; 00417 00418 return $trRec; 00419 00420 00421 } 00422 00435 public function scoreTranslation($string, $translation, $score, $username=null, $secure=false){ 00436 00437 if ( !$username ) $username = Dataface_AuthenticationTool::getInstance()->getLoggedInUserName(); 00438 $trec = $this->findTranslation($string, $translation); 00439 00440 if ( !$trec ){ 00441 $trec = $this->addTranslation($string, $translation, $username, $secure); 00442 } 00443 00444 if ( !$trec ){ 00445 throw new Exception("Could not find matching translation and failed to add one."); 00446 } 00447 00448 $arec = new Dataface_Record('xf_tm_translations_score', array()); 00449 $arec->setValues(array( 00450 'translation_id'=>$trec->val('translation_id'), 00451 'translation_memory_id'=>$this->_rec->val('translation_memory_id'), 00452 'username'=>$username, 00453 'score'=>$score 00454 )); 00455 $res = $arec->save($secure); 00456 if ( PEAR::isError($res) ){ 00457 throw new Exception("Failed to approve translation: ".$res->getMessage()); 00458 00459 } 00460 return $arec; 00461 00462 } 00463 00464 00479 public function setTranslationStatus($string, $translation, $status, $username=null, $secure=false){ 00480 if ( !$username ) $username = Dataface_AuthenticationTool::getInstance()->getLoggedInUserName(); 00481 $trec = $this->findTranslation($string, $translation); 00482 00483 if ( !$trec ){ 00484 $trec = $this->addTranslation($string, $translation, $username, $secure); 00485 } 00486 00487 if ( !$trec ){ 00488 throw new Exception("Could not find matching translation and failed to add one."); 00489 } 00490 00491 $arec = new Dataface_Record('xf_tm_translations_status', array()); 00492 $arec->setValues(array( 00493 'translation_id'=>$trec->val('translation_id'), 00494 'translation_memory_id'=>$this->_rec->val('translation_memory_id'), 00495 'username'=>$username, 00496 'status_id'=>$status 00497 )); 00498 $res = $arec->save($secure); 00499 if ( PEAR::isError($res) ){ 00500 throw new Exception("Failed to approve translation: ".$res->getMessage()); 00501 00502 } 00503 return $arec; 00504 } 00505 00506 00515 public function addTranslationComment($string, $translation, $comment, $username=null, $secure=false){ 00516 if ( !$username ) $username = Dataface_AuthenticationTool::getInstance()->getLoggedInUserName(); 00517 $trec = $this->findTranslation($string, $translation); 00518 00519 if ( !$trec ){ 00520 $trec = $this->addTranslation($string, $translation, $username, $secure); 00521 } 00522 00523 if ( !$trec ){ 00524 throw new Exception("Could not find matching translation and failed to add one."); 00525 } 00526 00527 $arec = new Dataface_Record('xf_tm_translations_comments', array()); 00528 $arec->setValues(array( 00529 'translation_id'=>$trec->val('translation_id'), 00530 'translation_memory_id'=>$this->_rec->val('translation_memory_id'), 00531 'posted_by'=>$username, 00532 'comments'=>$comment 00533 )); 00534 $res = $arec->save($secure); 00535 if ( PEAR::isError($res) ){ 00536 throw new Exception("Failed to approve translation: ".$res->getMessage()); 00537 00538 } 00539 return $arec; 00540 } 00541 00548 public function getTranslations(array $sources, $minStatus=3, $maxStatus=5){ 00549 $out = array(); 00550 $normalized = array(); 00551 $hashed = array(); 00552 $hashIndex = array(); 00553 $disqualified = array(); 00554 foreach ($sources as $k=>$src){ 00555 $normalized[$k] = TMTools::normalize($src); 00556 $hashed[$k] = md5($normalized[$k]); 00557 $hashIndex[$hashed[$k]] = $k; 00558 $out[$k] = null; 00559 } 00560 00561 $hashesStr = "'".implode("','", $hashed)."'"; 00562 if ( !$hashesStr ) $hashesStr = '0'; 00563 $hashesStr = '('.$hashesStr.')'; 00564 00565 00566 $sql = "select 00567 s.`hash`, 00568 t.translation_value, 00569 tts.status_id 00570 from 00571 xf_tm_translations t 00572 inner join xf_tm_translations_status tts on t.translation_id=tts.translation_id and tts.translation_memory_id='".addslashes($this->_rec->val('translation_memory_id'))."' 00573 inner join xf_tm_strings s on t.string_id=s.string_id 00574 where 00575 tts.translation_memory_id='".addslashes($this->_rec->val('translation_memory_id'))."' 00576 and s.`hash` in $hashesStr 00577 00578 order by tts.date_created desc"; 00579 $res = mysql_query($sql, df_db()); 00580 if ( !$res ) throw new Exception(mysql_error(df_db())); 00581 00582 while ($row = mysql_fetch_assoc($res) ){ 00583 $k = $hashIndex[$row['hash']]; 00584 if ( !isset($k) ){ 00585 throw new Exception("Invalid hash returned"); 00586 } 00587 if ( !isset($out[$k]) ){ 00588 if ( $row['status_id'] < $minStatus or $row['status_id'] > $maxStatus ){ 00589 $disqualified[$k] = true; 00590 } else if ( !@$disqualified[$k] ){ 00591 $out[$k] = $row['translation_value']; 00592 } 00593 } 00594 } 00595 @mysql_free_result($res); 00596 return $out; 00597 00598 00599 00600 } 00601 00602 00603 00604 }