poimport.php

Go to the documentation of this file.
00001 <?php
00012 // Standard boilerplate to define $IP
00013 if ( getenv( 'MW_INSTALL_PATH' ) !== false ) {
00014     $IP = getenv( 'MW_INSTALL_PATH' );
00015 } else {
00016     $dir = __DIR__;
00017     $IP = "$dir/../../..";
00018 }
00019 require_once "$IP/maintenance/Maintenance.php";
00020 
00021 class PoImport extends Maintenance {
00022     public function __construct() {
00023         parent::__construct();
00024         $this->mDescription = 'Po file importer (does not make changes unless specified).';
00025         $this->addOption(
00026             'file',
00027             'Gettext file to import (Translate specific formatting)',
00028             true, /*required*/
00029             true /*has arg*/
00030         );
00031         $this->addOption(
00032             'user',
00033             'User who makes edits to wiki',
00034             true, /*required*/
00035             true /*has arg*/
00036         );
00037         $this->addOption(
00038             'really',
00039             '(optional) Actually make changes',
00040             false, /*required*/
00041             false /*has arg*/
00042         );
00043     }
00044 
00045     public function execute() {
00046         // Parse the po file.
00047         $p = new PoImporter( $this->getOption( 'file' ) );
00048         $p->setProgressCallback( array( $this, 'myOutput' ) );
00049         list( $changes, $group ) = $p->parse();
00050 
00051         if ( !count( $changes ) ) {
00052             $this->output( "No changes to import\n" );
00053             exit( 0 );
00054         }
00055 
00056         // Import changes to wiki.
00057         $w = new WikiWriter(
00058             $changes,
00059             $group,
00060             $this->getOption( 'user' ),
00061             !$this->hasOption( 'really' )
00062         );
00063 
00064         $w->setProgressCallback( array( $this, 'myOutput' ) );
00065         $w->execute();
00066     }
00067 
00075     public function myOutput( $text, $channel = null, $error = false ) {
00076         if ( $error ) {
00077             $this->error( $text, $channel );
00078         } else {
00079             $this->output( $text, $channel );
00080         }
00081     }
00082 }
00083 
00088 class PoImporter {
00090     protected $progressCallback;
00091 
00096     private $file = false;
00097 
00101     public function __construct( $file ) {
00102         $this->file = $file;
00103     }
00104 
00105     public function setProgressCallback( $callback ) {
00106         $this->progressCallback = $callback;
00107     }
00108 
00110     protected function reportProgress( $text, $channel, $severity = 'status' ) {
00111         if ( is_callable( $this->progressCallback ) ) {
00112             $useErrorOutput = $severity === 'error';
00113             call_user_func( $this->progressCallback, $text, $channel, $useErrorOutput );
00114         }
00115     }
00116 
00124     protected function initMessages( $id, $code ) {
00125         $group = MessageGroups::getGroup( $id );
00126 
00127         $messages = $group->initCollection( $code );
00128         $messages->loadTranslations();
00129 
00130         return $messages;
00131     }
00132 
00137     public function parse() {
00138         $data = file_get_contents( $this->file );
00139         $data = str_replace( "\r\n", "\n", $data );
00140 
00141         $matches = array();
00142         if ( preg_match( '/X-Language-Code:\s+(.*)\\\n/', $data, $matches ) ) {
00143             $code = $matches[1];
00144             $this->reportProgress( "Detected language as $code", 'code' );
00145         } else {
00146             $this->reportProgress( 'Unable to determine language code', 'code', 'error' );
00147 
00148             return false;
00149         }
00150 
00151         if ( preg_match( '/X-Message-Group:\s+(.*)\\\n/', $data, $matches ) ) {
00152             $groupId = $matches[1];
00153             $this->reportProgress( "Detected message group as $groupId", 'group' );
00154         } else {
00155             $this->reportProgress( 'Unable to determine message group', 'group', 'error' );
00156 
00157             return false;
00158         }
00159 
00160         $contents = $this->initMessages( $groupId, $code );
00161 
00162         echo "----\n";
00163 
00164         $poformat = '".*"\n?(^".*"$\n?)*';
00165         $quotePattern = '/(^"|"$\n?)/m';
00166 
00167         $sections = preg_split( '/\n{2,}/', $data );
00168         $changes = array();
00169         foreach ( $sections as $section ) {
00170             $matches = array();
00171             if ( preg_match( "/^msgctxt\s($poformat)/mx", $section, $matches ) ) {
00172                 // Remove quoting
00173                 $key = preg_replace( $quotePattern, '', $matches[1] );
00174 
00175                 // Ignore unknown keys
00176                 if ( !isset( $contents[$key] ) ) {
00177                     continue;
00178                 }
00179             } else {
00180                 continue;
00181             }
00182             $matches = array();
00183             if ( preg_match( "/^msgstr\s($poformat)/mx", $section, $matches ) ) {
00184                 // Remove quoting
00185                 $translation = preg_replace( $quotePattern, '', $matches[1] );
00186                 // Restore new lines and remove quoting
00187                 $translation = stripcslashes( $translation );
00188             } else {
00189                 continue;
00190             }
00191 
00192             // Fuzzy messages
00193             if ( preg_match( '/^#, fuzzy$/m', $section ) ) {
00194                 $translation = TRANSLATE_FUZZY . $translation;
00195             }
00196 
00197             $oldtranslation = (string)$contents[$key]->translation();
00198 
00199             if ( $translation !== $oldtranslation ) {
00200                 if ( $translation === '' ) {
00201                     $this->reportProgress( "Skipping empty translation in the po file for $key!", 'empty' );
00202                 } else {
00203                     if ( $oldtranslation === '' ) {
00204                         $this->reportProgress( "New translation for $key", 'new' );
00205                     } else {
00206                         $this->reportProgress( "Translation of $key differs:\n$translation", 'differs' );
00207                     }
00208                     $changes["$key/$code"] = $translation;
00209                 }
00210             }
00211         }
00212 
00213         return array( $changes, $groupId );
00214     }
00215 }
00216 
00220 class WikiWriter {
00222     protected $progressCallback;
00223 
00224     private $changes = array();
00225     private $dryrun = true;
00226     private $allclear = false;
00227     private $group = null;
00228     protected $user;
00229 
00236     public function __construct( $changes, $groupId, $user, $dryrun = true ) {
00237         $this->changes = $changes;
00238         $this->group = MessageGroups::getGroup( $groupId );
00239         $this->user = User::newFromName( $user );
00240         $this->dryrun = $dryrun;
00241     }
00242 
00243     public function setProgressCallback( $callback ) {
00244         $this->progressCallback = $callback;
00245     }
00246 
00248     protected function reportProgress( $text, $channel, $severity = 'status' ) {
00249         if ( is_callable( $this->progressCallback ) ) {
00250             $useErrorOutput = $severity === 'error';
00251             call_user_func( $this->progressCallback, $text, $channel, $useErrorOutput );
00252         }
00253     }
00254 
00258     public function execute() {
00259         if ( !$this->group ) {
00260             $this->reportProgress( "Group $groupId does not exist.", 'groupId', 'error' );
00261 
00262             return;
00263         }
00264 
00265         if ( !$this->user->idForName() ) {
00266             $this->reportProgress( "User $user does not exist.", 'user', 'error' );
00267 
00268             return;
00269         }
00270 
00271         $count = count( $this->changes );
00272         $this->reportProgress( "Going to update $count pages.", 'pagecount' );
00273 
00274         $ns = $this->group->getNamespace();
00275 
00276         foreach ( $this->changes as $title => $text ) {
00277             $this->updateMessage( $ns, $title, $text );
00278         }
00279     }
00280 
00287     private function updateMessage( $namespace, $page, $text ) {
00288         $title = Title::makeTitleSafe( $namespace, $page );
00289 
00290         if ( !$title instanceof Title ) {
00291             $this->reportProgress( 'INVALID TITLE!', $page, 'error' );
00292 
00293             return;
00294         }
00295         $this->reportProgress( "Updating {$title->getPrefixedText()}... ", $title );
00296 
00297         if ( $this->dryrun ) {
00298             $this->reportProgress( 'DRY RUN!', $title );
00299 
00300             return;
00301         }
00302 
00303         $article = new Article( $title, 0 );
00304 
00305         $status = $article->doEdit(
00306             $text,
00307             'Updating translation from gettext import',
00308             0,
00309             false,
00310             $this->user
00311         );
00312 
00313         if ( $status === true || ( is_object( $status ) && $status->isOK() ) ) {
00314             $this->reportProgress( 'OK!', $title );
00315         } else {
00316             $this->reportProgress( 'Failed!', $title );
00317         }
00318     }
00319 }
00320 
00321 $maintClass = 'PoImport';
00322 require_once RUN_MAINTENANCE_IF_MAIN;
Generated on Tue Oct 29 00:00:24 2013 for MediaWiki Translate Extension by  doxygen 1.6.3