Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
TranslateRcFilter.php
Go to the documentation of this file.
1<?php
12use MediaWiki\MediaWikiServices;
13use MediaWiki\Storage\NameTableAccessException;
14
34 public static function translationFilter( $pageName, &$tables, &$fields, &$conds,
35 &$query_options, &$join_conds, FormOptions $opts
36 ) {
37 global $wgTranslateRcFilterDefault;
38
39 if ( $pageName !== 'Recentchanges' || self::isStructuredFilterUiEnabled() ) {
40 return true;
41 }
42
43 $request = RequestContext::getMain()->getRequest();
44 $translations = $request->getVal( 'translations', $wgTranslateRcFilterDefault );
45 $opts->add( 'translations', $wgTranslateRcFilterDefault );
46 $opts->setValue( 'translations', $translations );
47
48 $dbr = wfGetDB( DB_REPLICA );
49
50 $namespaces = self::getTranslateNamespaces();
51
52 if ( $translations === 'only' ) {
53 $conds[] = 'rc_namespace IN (' . $dbr->makeList( $namespaces ) . ')';
54 $conds[] = 'rc_title like \'%%/%%\'';
55 } elseif ( $translations === 'filter' ) {
56 $conds[] = 'rc_namespace NOT IN (' . $dbr->makeList( $namespaces ) . ')';
57 } elseif ( $translations === 'site' ) {
58 $conds[] = 'rc_namespace IN (' . $dbr->makeList( $namespaces ) . ')';
59 $conds[] = 'rc_title not like \'%%/%%\'';
60 }
61
62 return true;
63 }
64
65 private static function getTranslateNamespaces() {
66 global $wgTranslateMessageNamespaces;
67 $namespaces = [];
68
69 foreach ( $wgTranslateMessageNamespaces as $index ) {
70 $namespaces[] = $index;
71 $namespaces[] = $index + 1; // Include Talk namespaces
72 }
73
74 return $namespaces;
75 }
76
86 public static function translationFilterForm( &$items, $opts ) {
87 if ( self::isStructuredFilterUiEnabled() ) {
88 return true;
89 }
90
91 $opts->consumeValue( 'translations' );
92 $default = $opts->getValue( 'translations' );
93
94 $label = Xml::label(
95 wfMessage( 'translate-rc-translation-filter' )->text(),
96 'mw-translation-filter'
97 );
98 $select = new XmlSelect( 'translations', 'mw-translation-filter', $default );
99 $select->addOption(
100 wfMessage( 'translate-rc-translation-filter-no' )->text(),
101 'noaction'
102 );
103 $select->addOption( wfMessage( 'translate-rc-translation-filter-only' )->text(), 'only' );
104 $select->addOption(
105 wfMessage( 'translate-rc-translation-filter-filter' )->text(),
106 'filter'
107 );
108 $select->addOption( wfMessage( 'translate-rc-translation-filter-site' )->text(), 'site' );
109
110 $items['translations'] = [ $label, $select->getHTML() ];
111
112 return true;
113 }
114
115 private static function isStructuredFilterUiEnabled() {
116 $context = RequestContext::getMain();
117
118 // This assumes usage only on RC page
119 $page = new SpecialRecentChanges();
120 $page->setContext( $context );
121
122 // isStructuredFilterUiEnabled used to be a protected method in older versions :(
123 return is_callable( [ $page, 'isStructuredFilterUiEnabled' ] ) &&
124 $page->isStructuredFilterUiEnabled();
125 }
126
136 ChangesListSpecialPage $special
137 ) {
138 global $wgTranslateRcFilterDefault;
139 $defaultFilter = $wgTranslateRcFilterDefault !== 'noaction' ?
140 $wgTranslateRcFilterDefault :
141 ChangesListStringOptionsFilterGroup::NONE;
142
143 $translationsGroup = new ChangesListStringOptionsFilterGroup(
144 [
145 'name' => 'translations',
146 'title' => 'translate-rcfilters-translations',
147 'priority' => -7,
148 'default' => $defaultFilter,
149 'isFullCoverage' => true,
150 'filters' => [
151 [
152 'name' => 'only',
153 'label' => 'translate-rcfilters-translations-only-label',
154 'description' => 'translate-rcfilters-translations-only-desc',
155 'cssClassSuffix' => 'only',
156 'isRowApplicableCallable' => function ( $ctx, $rc ) {
157 $namespaces = self::getTranslateNamespaces();
158
159 return in_array( $rc->getAttribute( 'rc_namespace' ), $namespaces ) &&
160 !str_contains( $rc->getAttribute( 'rc_title' ), '/' );
161 }
162 ],
163 [
164 'name' => 'site',
165 'label' => 'translate-rcfilters-translations-site-label',
166 'description' => 'translate-rcfilters-translations-site-desc',
167 'cssClassSuffix' => 'site',
168 'isRowApplicableCallable' => function ( $ctx, $rc ) {
169 $namespaces = self::getTranslateNamespaces();
170
171 return in_array( $rc->getAttribute( 'rc_namespace' ), $namespaces ) &&
172 !str_contains( $rc->getAttribute( 'rc_title' ), '/' );
173 }
174 ],
175 [
176 'name' => 'filter',
177 'label' => 'translate-rcfilters-translations-filter-label',
178 'description' => 'translate-rcfilters-translations-filter-desc',
179 'cssClassSuffix' => 'filter',
180 'isRowApplicableCallable' => function ( $ctx, $rc ) {
181 $namespaces = self::getTranslateNamespaces();
182
183 return !in_array( $rc->getAttribute( 'rc_namespace' ), $namespaces );
184 }
185 ],
186 [
187 'name' => 'filter-translation-pages',
188 'label' => 'translate-rcfilters-translations-filter-translation-pages-label',
189 'description' => 'translate-rcfilters-translations-filter-translation-pages-desc',
190 'cssClassSuffix' => 'filter-translation-pages',
191 'isRowApplicableCallable' => static function ( $ctx, $rc ) {
192 $tags = explode( ', ', $rc->getAttribute( 'ts_tags' ) ?? '' );
193 return !in_array( 'translate-filter-translation-pages', $tags );
194 }
195 ],
196
197 ],
198 'queryCallable' => function ( $specialClassName, $ctx, $dbr, &$tables,
199 &$fields, &$conds, &$query_options, &$join_conds, $selectedValues
200 ) {
201 $fields = array_merge( $fields, [ 'rc_title', 'rc_namespace' ] );
202
203 // Handle changes to translation pages separately
204 $filterRenderedIndex = array_search( 'filter-translation-pages', $selectedValues );
205 if ( $filterRenderedIndex !== false ) {
206 unset( $selectedValues[$filterRenderedIndex] );
207 $selectedValues = array_values( $selectedValues );
208
209 $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
210 try {
211 $renderedPage = $changeTagDefStore->getId( 'translate-translation-pages' );
212 $tables['translatetags'] = ChangeTags::getDisplayTableName();
213 $join_conds['translatetags'] = [
214 'LEFT JOIN',
215 [ 'translatetags.ct_rc_id=rc_id', 'translatetags.ct_tag_id' => $renderedPage ]
216 ];
217 $conds['translatetags.ct_tag_id'] = null;
218 } catch ( NameTableAccessException $exception ) {
219 // Tag name does not yet exist in DB.
220 }
221 }
222
223 $namespaces = self::getTranslateNamespaces();
224 $inNamespaceCond = 'rc_namespace IN (' .
225 $dbr->makeList( $namespaces ) . ')';
226 $notInNamespaceCond = 'rc_namespace NOT IN (' .
227 $dbr->makeList( $namespaces ) . ')';
228
229 $onlyCond = $dbr->makeList( [
230 $inNamespaceCond,
231 'rc_title ' .
232 $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString() )
233 ], LIST_AND );
234 $siteCond = $dbr->makeList( [
235 $inNamespaceCond,
236 'rc_title NOT' .
237 $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString() )
238 ], LIST_AND );
239
240 if ( count( $selectedValues ) === 3 ) {
241 // no filters
242 return;
243 }
244
245 if ( $selectedValues === [ 'filter', 'only' ] ) {
246 $conds[] = $dbr->makeList( [
247 $notInNamespaceCond,
248 $onlyCond
249 ], LIST_OR );
250 return;
251 }
252
253 if ( $selectedValues === [ 'filter', 'site' ] ) {
254 $conds[] = $dbr->makeList( [
255 $notInNamespaceCond,
256 $siteCond
257 ], LIST_OR );
258 return;
259 }
260
261 if ( $selectedValues === [ 'only', 'site' ] ) {
262 $conds[] = $inNamespaceCond;
263 return;
264 }
265
266 if ( $selectedValues === [ 'filter' ] ) {
267 $conds[] = $notInNamespaceCond;
268 return;
269 }
270
271 if ( $selectedValues === [ 'only' ] ) {
272 $conds[] = $onlyCond;
273 return;
274 }
275
276 if ( $selectedValues === [ 'site' ] ) {
277 $conds[] = $siteCond;
278 }
279 }
280 ]
281 );
282
283 $special->registerFilterGroup( $translationsGroup );
284 return true;
285 }
286}
Adds a new filter to Special:RecentChanges which makes it possible to filter translations away or sho...
static translationFilter( $pageName, &$tables, &$fields, &$conds, &$query_options, &$join_conds, FormOptions $opts)
Hooks ChangesListSpecialPageQuery.
static onChangesListSpecialPageStructuredFilters(ChangesListSpecialPage $special)
Hooks ChangesListSpecialPageStructuredFilters.
static translationFilterForm(&$items, $opts)
Hooks SpecialRecentChangesPanel.