Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4126759
poimport.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
poimport.php
View Options
<?php
/**
* Imports gettext files exported from Special:Translate back.
*
* @author Niklas Laxström
* @author Siebrand Mazeland
* @copyright Copyright © 2007-2013 Niklas Laxström, Siebrand Mazeland
* @license GPL-2.0-or-later
* @file
*/
use
MediaWiki\CommentStore\CommentStoreComment
;
use
MediaWiki\Extension\Translate\MessageGroupProcessing\MessageGroups
;
use
MediaWiki\Extension\Translate\MessageLoading\MessageCollection
;
use
MediaWiki\MediaWikiServices
;
use
MediaWiki\Revision\SlotRecord
;
use
MediaWiki\Title\Title
;
use
MediaWiki\User\User
;
// Standard boilerplate to define $IP
if
(
getenv
(
'MW_INSTALL_PATH'
)
!==
false
)
{
$IP
=
getenv
(
'MW_INSTALL_PATH'
);
}
else
{
$dir
=
__DIR__
;
$IP
=
"$dir/../../.."
;
}
require_once
"$IP/maintenance/Maintenance.php"
;
class
Poimport
extends
Maintenance
{
public
function
__construct
()
{
parent
::
__construct
();
$this
->
addDescription
(
'Po file importer (does not make changes unless specified).'
);
$this
->
addOption
(
'file'
,
'Gettext file to import (Translate specific formatting)'
,
true
,
/*required*/
true
/*has arg*/
);
$this
->
addOption
(
'user'
,
'User who makes edits to wiki'
,
true
,
/*required*/
true
/*has arg*/
);
$this
->
addOption
(
'really'
,
'(optional) Actually make changes'
,
false
,
/*required*/
false
/*has arg*/
);
$this
->
requireExtension
(
'Translate'
);
}
public
function
execute
()
{
// Parse the po file.
$p
=
new
PoImporter
(
$this
->
getOption
(
'file'
)
);
$p
->
setProgressCallback
(
[
$this
,
'myOutput'
]
);
[
$changes
,
$group
]
=
$p
->
parse
();
if
(
!
count
(
$changes
)
)
{
$this
->
output
(
"No changes to import
\n
"
);
exit
(
0
);
}
// Import changes to wiki.
$w
=
new
WikiWriter
(
$changes
,
$group
,
$this
->
getOption
(
'user'
),
!
$this
->
hasOption
(
'really'
)
);
$w
->
setProgressCallback
(
[
$this
,
'myOutput'
]
);
$w
->
execute
();
}
/**
* Public alternative for protected Maintenance::output() as we need to get
* messages from the ChangeSyncer class to the commandline.
* @param string $text The text to show to the user
* @param string|null $channel Unique identifier for the channel.
* @param bool $error Whether this is an error message
*/
public
function
myOutput
(
$text
,
$channel
=
null
,
$error
=
false
)
{
if
(
$error
)
{
$this
->
error
(
$text
);
}
else
{
$this
->
output
(
$text
,
$channel
);
}
}
}
/**
* Parses a po file that has been exported from MediaWiki. Other files are not
* supported.
*/
class
PoImporter
{
/** @var callable Function to report progress updates */
private
$progressCallback
;
/**
* Path to file to parse.
* @var string
*/
private
$file
;
/** @param string $file File to import */
public
function
__construct
(
$file
)
{
$this
->
file
=
$file
;
}
public
function
setProgressCallback
(
$callback
)
{
$this
->
progressCallback
=
$callback
;
}
/// @see Maintenance::output for param docs
protected
function
reportProgress
(
$text
,
$channel
=
null
,
$severity
=
'status'
)
{
if
(
is_callable
(
$this
->
progressCallback
)
)
{
$useErrorOutput
=
$severity
===
'error'
;
call_user_func
(
$this
->
progressCallback
,
$text
,
$channel
,
$useErrorOutput
);
}
}
/**
* Loads translations for comparison.
*
* @param string $id Id of MessageGroup.
* @param string $code Language code.
* @return MessageCollection
*/
protected
function
initMessages
(
$id
,
$code
)
{
$group
=
MessageGroups
::
getGroup
(
$id
);
$messages
=
$group
->
initCollection
(
$code
);
$messages
->
loadTranslations
();
return
$messages
;
}
/**
* Parses relevant stuff from the po file.
* @return array|bool
*/
public
function
parse
()
{
$data
=
file_get_contents
(
$this
->
file
);
$data
=
TextContent
::
normalizeLineEndings
(
$data
);
$matches
=
[];
if
(
preg_match
(
'/X-Language-Code:
\s
+(.*)
\\\n
/'
,
$data
,
$matches
)
)
{
$code
=
$matches
[
1
];
$this
->
reportProgress
(
"Detected language as $code"
,
'code'
);
}
else
{
$this
->
reportProgress
(
'Unable to determine language code'
,
'code'
,
'error'
);
return
false
;
}
if
(
preg_match
(
'/X-Message-Group:
\s
+(.*)
\\\n
/'
,
$data
,
$matches
)
)
{
$groupId
=
$matches
[
1
];
$this
->
reportProgress
(
"Detected message group as $groupId"
,
'group'
);
}
else
{
$this
->
reportProgress
(
'Unable to determine message group'
,
'group'
,
'error'
);
return
false
;
}
$contents
=
$this
->
initMessages
(
$groupId
,
$code
);
echo
"----
\n
"
;
$poformat
=
'".*"
\n
?(^".*"$
\n
?)*'
;
$quotePattern
=
'/(^"|"$
\n
?)/m'
;
$sections
=
preg_split
(
'/
\n
{2,}/'
,
$data
);
$changes
=
[];
foreach
(
$sections
as
$section
)
{
$matches
=
[];
if
(
preg_match
(
"/^msgctxt
\s
($poformat)/mx"
,
$section
,
$matches
)
)
{
// Remove quoting
$key
=
preg_replace
(
$quotePattern
,
''
,
$matches
[
1
]
);
// Ignore unknown keys
if
(
!
isset
(
$contents
[
$key
]
)
)
{
continue
;
}
}
else
{
continue
;
}
$matches
=
[];
if
(
preg_match
(
"/^msgstr
\s
($poformat)/mx"
,
$section
,
$matches
)
)
{
// Remove quoting
$translation
=
preg_replace
(
$quotePattern
,
''
,
$matches
[
1
]
);
// Restore new lines and remove quoting
$translation
=
stripcslashes
(
$translation
);
}
else
{
continue
;
}
// Fuzzy messages
if
(
preg_match
(
'/^#, fuzzy$/m'
,
$section
)
)
{
$translation
=
TRANSLATE_FUZZY
.
$translation
;
}
$oldtranslation
=
(
string
)
$contents
[
$key
]->
translation
();
if
(
$translation
!==
$oldtranslation
)
{
if
(
$translation
===
''
)
{
$this
->
reportProgress
(
"Skipping empty translation in the po file for $key!
\n
"
);
}
else
{
if
(
$oldtranslation
===
''
)
{
$this
->
reportProgress
(
"New translation for $key
\n
"
);
}
else
{
$this
->
reportProgress
(
"Translation of $key differs:
\n
$translation
\n
"
);
}
$changes
[
"$key/$code"
]
=
$translation
;
}
}
}
return
[
$changes
,
$groupId
];
}
}
/**
* Import changes to wiki as given user
*/
class
WikiWriter
{
/** @var callable|null Function to report progress updates */
private
$progressCallback
;
/** @var User */
private
$user
;
/** @var string[] */
private
$changes
;
/** @var bool */
private
$dryrun
;
/** @var MessageGroup|null */
private
$group
;
/**
* @param string[] $changes Array of key/langcode => translation.
* @param string $groupId
* @param string $user User who makes the edits in wiki.
* @param bool $dryrun Do not do anything that affects the database.
*/
public
function
__construct
(
array
$changes
,
$groupId
,
$user
,
$dryrun
=
true
)
{
$this
->
changes
=
$changes
;
$this
->
group
=
MessageGroups
::
getGroup
(
$groupId
);
$this
->
user
=
MediaWikiServices
::
getInstance
()
->
getUserFactory
()
->
newFromName
(
$user
);
$this
->
dryrun
=
$dryrun
;
}
public
function
setProgressCallback
(
$callback
)
{
$this
->
progressCallback
=
$callback
;
}
/// @see Maintenance::output for param docs
protected
function
reportProgress
(
$text
,
$channel
,
$severity
=
'status'
)
{
if
(
is_callable
(
$this
->
progressCallback
)
)
{
$useErrorOutput
=
$severity
===
'error'
;
call_user_func
(
$this
->
progressCallback
,
$text
,
$channel
,
$useErrorOutput
);
}
}
/**
* Updates pages on by one.
*/
public
function
execute
()
{
if
(
!
$this
->
group
)
{
$this
->
reportProgress
(
'Given group does not exist.'
,
'groupId'
,
'error'
);
return
;
}
if
(
!
$this
->
user
->
idForName
()
)
{
$this
->
reportProgress
(
'Given user does not exist.'
,
'user'
,
'error'
);
return
;
}
$count
=
count
(
$this
->
changes
);
$this
->
reportProgress
(
"Going to update $count pages."
,
'pagecount'
);
$ns
=
$this
->
group
->
getNamespace
();
foreach
(
$this
->
changes
as
$title
=>
$text
)
{
$this
->
updateMessage
(
$ns
,
$title
,
$text
);
}
}
/**
* Actually adds the new translation.
* @param int $namespace
* @param string $page
* @param string $text
*/
private
function
updateMessage
(
$namespace
,
$page
,
$text
)
{
$title
=
Title
::
makeTitleSafe
(
$namespace
,
$page
);
if
(
!
$title
instanceof
Title
)
{
$this
->
reportProgress
(
'INVALID TITLE!'
,
$page
,
'error'
);
return
;
}
$this
->
reportProgress
(
"Updating {$title->getPrefixedText()}... "
,
$title
);
if
(
$this
->
dryrun
)
{
$this
->
reportProgress
(
'DRY RUN!'
,
$title
);
return
;
}
$page
=
MediaWikiServices
::
getInstance
()->
getWikiPageFactory
()->
newFromTitle
(
$title
);
$content
=
ContentHandler
::
makeContent
(
$text
,
$title
);
$updater
=
$page
->
newPageUpdater
(
$this
->
user
)->
setContent
(
SlotRecord
::
MAIN
,
$content
);
if
(
$this
->
user
->
authorizeWrite
(
'autopatrol'
,
$title
)
)
{
$updater
->
setRcPatrolStatus
(
RecentChange
::
PRC_AUTOPATROLLED
);
}
$summary
=
CommentStoreComment
::
newUnsavedComment
(
'Updating translation from gettext import'
);
$updater
->
saveRevision
(
$summary
);
$status
=
$updater
->
getStatus
();
if
(
$status
->
isOK
()
)
{
$this
->
reportProgress
(
'OK!'
,
$title
);
}
else
{
$this
->
reportProgress
(
'Failed!'
,
$title
);
}
}
}
$maintClass
=
Poimport
::
class
;
require_once
RUN_MAINTENANCE_IF_MAIN
;
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Wed, Aug 19, 08:15 (2 w, 3 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
e4/65/5ec9da94e7237d2a82136e478248
Default Alt Text
poimport.php (8 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment