12use MediaWiki\CommentStore\CommentStoreComment;
13use MediaWiki\Content\ContentHandler;
14use MediaWiki\Content\TextContent;
17use MediaWiki\Maintenance\Maintenance;
18use MediaWiki\MediaWikiServices;
19use MediaWiki\Revision\SlotRecord;
20use MediaWiki\Title\Title;
21use MediaWiki\User\User;
24if ( getenv(
'MW_INSTALL_PATH' ) !==
false ) {
25 $IP = getenv(
'MW_INSTALL_PATH' );
28 $IP =
"$dir/../../..";
30require_once
"$IP/maintenance/Maintenance.php";
33 public function __construct() {
34 parent::__construct();
35 $this->addDescription(
'Po file importer (does not make changes unless specified).' );
38 'Gettext file to import (Translate specific formatting)',
44 'User who makes edits to wiki',
50 '(optional) Actually make changes',
54 $this->requireExtension(
'Translate' );
57 public function execute() {
59 $p =
new PoImporter( $this->getOption(
'file' ) );
60 $p->setProgressCallback( [ $this,
'myOutput' ] );
61 [ $changes, $group ] = $p->parse();
63 if ( !count( $changes ) ) {
64 $this->output(
"No changes to import\n" );
72 $this->getOption(
'user' ),
73 !$this->hasOption(
'really' )
76 $w->setProgressCallback( [ $this,
'myOutput' ] );
87 public function myOutput( $text, $channel =
null, $error =
false ) {
89 $this->error( $text );
91 $this->output( $text, $channel );
102 private $progressCallback;
114 public function setProgressCallback( $callback ) {
115 $this->progressCallback = $callback;
119 protected function reportProgress( $text, $channel =
null, $severity =
'status' ) {
120 if ( is_callable( $this->progressCallback ) ) {
121 $useErrorOutput = $severity ===
'error';
122 call_user_func( $this->progressCallback, $text, $channel, $useErrorOutput );
134 $group = MessageGroups::getGroup( $id );
136 $messages = $group->initCollection( $code );
137 $messages->loadTranslations();
147 $data = file_get_contents( $this->file );
148 $data = TextContent::normalizeLineEndings( $data );
151 if ( preg_match(
'/X-Language-Code:\s+(.*)\\\n/', $data, $matches ) ) {
155 $this->
reportProgress(
'Unable to determine language code',
'code',
'error' );
160 if ( preg_match(
'/X-Message-Group:\s+(.*)\\\n/', $data, $matches ) ) {
161 $groupId = $matches[1];
162 $this->
reportProgress(
"Detected message group as $groupId",
'group' );
164 $this->
reportProgress(
'Unable to determine message group',
'group',
'error' );
173 $poformat =
'".*"\n?(^".*"$\n?)*';
174 $quotePattern =
'/(^"|"$\n?)/m';
176 $sections = preg_split(
'/\n{2,}/', $data );
178 foreach ( $sections as $section ) {
180 if ( preg_match(
"/^msgctxt\s($poformat)/mx", $section, $matches ) ) {
182 $key = preg_replace( $quotePattern,
'', $matches[1] );
185 if ( !isset( $contents[$key] ) ) {
192 if ( preg_match(
"/^msgstr\s($poformat)/mx", $section, $matches ) ) {
194 $translation = preg_replace( $quotePattern,
'', $matches[1] );
196 $translation = stripcslashes( $translation );
202 if ( preg_match(
'/^#, fuzzy$/m', $section ) ) {
203 $translation = TRANSLATE_FUZZY . $translation;
206 $oldtranslation = (string)$contents[$key]->translation();
208 if ( $translation !== $oldtranslation ) {
209 if ( $translation ===
'' ) {
210 $this->
reportProgress(
"Skipping empty translation in the po file for $key!\n" );
212 if ( $oldtranslation ===
'' ) {
215 $this->
reportProgress(
"Translation of $key differs:\n$translation\n" );
217 $changes[
"$key/$code"] = $translation;
222 return [ $changes, $groupId ];
231 private $progressCallback;
247 public function __construct( array $changes, $groupId, $user, $dryrun =
true ) {
248 $this->changes = $changes;
249 $this->group = MessageGroups::getGroup( $groupId );
250 $this->user = MediaWikiServices::getInstance()
252 ->newFromName( $user );
253 $this->dryrun = $dryrun;
256 public function setProgressCallback( $callback ) {
257 $this->progressCallback = $callback;
262 if ( is_callable( $this->progressCallback ) ) {
263 $useErrorOutput = $severity ===
'error';
264 call_user_func( $this->progressCallback, $text, $channel, $useErrorOutput );
272 if ( !$this->group ) {
273 $this->
reportProgress(
'Given group does not exist.',
'groupId',
'error' );
278 if ( !$this->user->idForName() ) {
279 $this->
reportProgress(
'Given user does not exist.',
'user',
'error' );
284 $count = count( $this->changes );
285 $this->
reportProgress(
"Going to update $count pages.",
'pagecount' );
287 $ns = $this->group->getNamespace();
289 foreach ( $this->changes as $title => $text ) {
290 $this->updateMessage( $ns, $title, $text );
300 private function updateMessage( $namespace, $page, $text ) {
301 $title = Title::makeTitleSafe( $namespace, $page );
303 if ( !$title instanceof Title ) {
308 $this->
reportProgress(
"Updating {$title->getPrefixedText()}... ", $title );
310 if ( $this->dryrun ) {
316 $page = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $title );
317 $content = ContentHandler::makeContent( $text, $title );
318 $updater = $page->newPageUpdater( $this->user )->setContent( SlotRecord::MAIN, $content );
320 if ( $this->user->authorizeWrite(
'autopatrol', $title ) ) {
321 $updater->setRcPatrolStatus( RecentChange::PRC_AUTOPATROLLED );
324 $summary = CommentStoreComment::newUnsavedComment(
'Updating translation from gettext import' );
325 $updater->saveRevision( $summary );
326 $status = $updater->getStatus();
328 if ( $status->isOK() ) {
336$maintClass = Poimport::class;
337require_once RUN_MAINTENANCE_IF_MAIN;
Parses a po file that has been exported from MediaWiki.
parse()
Parses relevant stuff from the po file.
reportProgress( $text, $channel=null, $severity='status')
initMessages( $id, $code)
Loads translations for comparison.
myOutput( $text, $channel=null, $error=false)
Public alternative for protected Maintenance::output() as we need to get messages from the ChangeSync...
Import changes to wiki as given user.
execute()
Updates pages on by one.
__construct(array $changes, $groupId, $user, $dryrun=true)
reportProgress( $text, $channel, $severity='status')