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.
Factory class for accessing message groups individually by id or all of them as a list.
Constants for making code for maintenance scripts more readable.