25 private $contentLanguage;
27 public function __construct() {
28 parent::__construct();
29 $this->addDescription(
'Creates a dump file that can be imported to a TTMServer' );
33 'Which directory to output files to',
40 'How many threads to use',
46 $availableMethods = array_keys( $this->getAvailableCompressionWrappers() );
47 $values = count( $availableMethods ) ? implode(
', ', $availableMethods ) :
'NONE';
50 "Use a compression filter. Possible values: $values",
56 $this->requireExtension(
'Translate' );
60 private function getAvailableCompressionWrappers(): array {
62 $filters = stream_get_filters();
63 foreach ( $filters as $f ) {
64 if ( preg_match(
'/^compress\..+$/', $f ) ) {
65 $out[$f] = $f .
'://';
71 public function execute() {
72 $this->contentLanguage = MediaWikiServices::getInstance()->getContentLanguage();
74 $threads = (int)$this->getOption(
'threads', 1 );
75 $outputDir = $this->getOption(
'output-directory' );
76 $requestedWrapper = $this->getOption(
'compress' );
77 $availableWrappers = $this->getAvailableCompressionWrappers();
78 if ( $requestedWrapper && !isset( $availableWrappers[$requestedWrapper] ) ) {
80 "Compression wrapper '$requestedWrapper' is not supported"
83 $wrapper = $availableWrappers[$requestedWrapper] ??
'';
84 $suffix = $requestedWrapper ?
".$requestedWrapper" :
'';
88 $groups = $this->getGroupsInPerformanceOrder();
89 foreach ( $groups as $groupId => $group ) {
90 $path = $wrapper . rtrim( $outputDir,
'/' ) .
'/' . $groupId .
'.json' . $suffix;
92 $executor->runInParallel(
93 function (
int $pid ) use ( $groupId ) {
94 $this->output(
"Forked process $pid to process $groupId\n" );
96 function () use ( $group, $path ) {
97 $output = FormatJson::encode(
98 $this->getOutput( $group ),
102 file_put_contents( $path, $output );
107 $this->output(
"Done.\n" );
120 private function getGroupsInPerformanceOrder(): array {
121 $groupStats = MessageGroupStats::forLanguage(
122 $this->contentLanguage->getCode(),
123 MessageGroupStats::FLAG_CACHE_ONLY
128 function ( array $a, array $b ):
int {
129 return -1 * $this->sortGroupsBySize( $a, $b );
134 foreach ( array_keys( $groupStats ) as $groupId ) {
135 $group = MessageGroups::getGroup( $groupId );
136 if ( $group->isMeta() ) {
140 $groups[$group->getId()] = $group;
146 private function sortGroupsBySize( array $a, array $b ):
int {
147 return $a[MessageGroupStats::TOTAL] <=> $b[MessageGroupStats::TOTAL];
150 private function getOutput(
MessageGroup $group ): array {
153 $groupId = $group->
getId();
156 $stats = MessageGroupStats::forGroup( $groupId );
158 foreach ( $stats as $language => $numbers ) {
159 if ( $numbers[MessageGroupStats::TRANSLATED] === 0 ) {
163 $collection->resetForNewLanguage( $language );
164 $collection->filter(
'ignored' );
165 $collection->filter(
'translated',
false );
166 $collection->loadTranslations();
168 foreach ( $collection->keys() as $mkey => $titleValue ) {
171 $message = $collection[$mkey];
173 if ( !isset( $out[$mkey] ) ) {
175 'wikiId' => WikiMap::getCurrentWikiId(),
176 'title' => $handle->getTitleForBase()->getPrefixedText(),
177 'sourceLanguage' => $sourceLanguage,
178 'primaryGroup' => $groupId,
183 $out[$mkey][
'values'][] = [
184 'language' => $language,
185 'value' => $message->translation(),
186 'revision' => $message->getProperty(
'revision' ),
191 return array_values( $out );