Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
FindUnsynchronizedDefinitionsMaintenanceScript.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\Diagnostics;
5
9use Title;
10
17 public function __construct() {
18 parent::__construct();
19 $this->addDescription(
20 'This scripts finds definition pages in the wiki that do not have the expected ' .
21 'content with regards to the message group definition cache for file based message ' .
22 'groups. This causes the definition diff to appear for translations when it should ' .
23 'not. See https://phabricator.wikimedia.org/T270844'
24 );
25
26 $this->addArg(
27 'group-pattern',
28 'For example page-*,main',
29 self::REQUIRED
30 );
31 $this->addOption(
32 'ignore-trailing-whitespace',
33 'Ignore trailing whitespace',
34 self::OPTIONAL,
35 self::NO_ARG,
36 'w'
37 );
38 $this->addOption(
39 'fix',
40 'Try to fix the issues by triggering reprocessing'
41 );
42
43 $this->requireExtension( 'Translate' );
44 }
45
47 public function execute() {
48 $spec = $this->getArg( 0 );
49 $ignoreTrailingWhitespace = $this->getOption( 'ignore-trailing-whitespace' );
50 $patterns = explode( ',', trim( $spec ) );
51 $groupIds = MessageGroups::expandWildcards( $patterns );
52 $groups = MessageGroups::getGroupsById( $groupIds );
53
54 foreach ( $groups as $index => $group ) {
55 if ( !$group instanceof FileBasedMessageGroup ) {
56 unset( $groups[ $index ] );
57 }
58 }
59
60 $matched = count( $groups );
61 $this->output( "Pattern matched $matched file based message group(s).\n" );
62 $this->output( "Left side is the expected value. Right side is the actual value in wiki.\n" );
63
64 $groupsWithIssues = [];
65 foreach ( $groups as $group ) {
66 $sourceLanguage = $group->getSourceLanguage();
67 $collection = $group->initCollection( $sourceLanguage );
68 $collection->loadTranslations();
69
70 foreach ( $collection->keys() as $mkey => $title ) {
71 $message = $collection[$mkey];
72 $definition = $message->definition() ?? '';
73 $translation = $message->translation() ?? '';
74
75 $differs = $ignoreTrailingWhitespace
76 ? rtrim( $definition ) !== $translation
77 : $definition !== $translation;
78
79 if ( $differs ) {
80 $groupsWithIssues[$group->getId()] = $group;
81 echo Title::newFromLinkTarget( $title )->getPrefixedText() . "\n";
82 echo $this->getSideBySide( "'$definition'", "'$translation'", 80 ) . "\n";
83 }
84 }
85 }
86
87 if ( $this->hasOption( 'fix' ) && $groupsWithIssues ) {
88 foreach ( $groupsWithIssues as $group ) {
89 '@phan-var FileBasedMessageGroup $group';
90 $cache = $group->getMessageGroupCache( $group->getSourceLanguage() );
91 $cache->invalidate();
92 }
93 $script = realpath( __DIR__ . '/../../scripts/processMessageChanges.php' );
94 $groupPattern = implode( ',', array_keys( $groupsWithIssues ) );
95 $command = "php '$script' --group='$groupPattern'";
96 echo "Now run the following command and finish the sync in the wiki:\n$command\n";
97 }
98 }
99
100 private function getSideBySide( string $a, string $b, int $width ): string {
101 $wrapWidth = (int)floor( ( $width - 3 ) / 2 );
102 $aArray = explode( "\n", wordwrap( $a, $wrapWidth, "\n", true ) );
103 $bArray = explode( "\n", wordwrap( $b, $wrapWidth, "\n", true ) );
104 $lines = max( count( $aArray ), count( $bArray ) );
105
106 $out = '';
107 for ( $i = 0; $i < $lines; $i++ ) {
108 $out .= sprintf(
109 "%-{$wrapWidth}s | %-{$wrapWidth}s\n",
110 $aArray[$i] ?? '',
111 $bArray[$i] ?? ''
112 );
113 }
114 return $out;
115 }
116}
This class implements default behavior for file based message groups.
Constants for making code for maintenance scripts more readable.
Factory class for accessing message groups individually by id or all of them as an list.