Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
10.23% covered (danger)
10.23%
143 / 1398
31.58% covered (danger)
31.58%
6 / 19
CRAP
0.00% covered (danger)
0.00%
0 / 1
Hooks
10.23% covered (danger)
10.23%
143 / 1398
31.58% covered (danger)
31.58%
6 / 19
6624.15
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 factory
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 onMessageCacheFetchOverrides
79.70% covered (warning)
79.70%
106 / 133
0.00% covered (danger)
0.00%
0 / 1
19.42
 getShortRightsLink
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 onSkinCopyrightFooterMessage
7.41% covered (danger)
7.41%
2 / 27
0.00% covered (danger)
0.00%
0 / 1
126.31
 onEditPageCopyrightWarning
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
72
 onDiscussionToolsTermsOfUseMessages
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
72
 onFlowTermsOfUseMessages
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
72
 onSkinAddFooterLinks
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
12
 onTorBlockBlockedMsg
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onUploadForm_initial
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 onRegistration
0.00% covered (danger)
0.00%
0 / 1060
0.00% covered (danger)
0.00%
0 / 1
6
 onOutputPageBeforeHTML
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 onResourceLoaderRegisterModules
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 onSpecialPageBeforeExecute
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addIPInfoLinks
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
72
 shouldMoveDonateLink
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 onSkinTemplateNavigation__Universal
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
3
 onSidebarBeforeOutput
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
7
1<?php
2
3namespace MediaWiki\Extension\WikimediaMessages;
4
5use HtmlArmor;
6use MediaWiki\Cache\Hook\MessageCacheFetchOverridesHook;
7use MediaWiki\Config\Config;
8use MediaWiki\Config\ConfigException;
9use MediaWiki\Config\ServiceOptions;
10use MediaWiki\Exception\ErrorPageError;
11use MediaWiki\Extension\WikimediaMessages\LogFormatter\WMUserMergeLogFormatter;
12use MediaWiki\Hook\EditPageCopyrightWarningHook;
13use MediaWiki\Hook\SidebarBeforeOutputHook;
14use MediaWiki\Hook\SkinAddFooterLinksHook;
15use MediaWiki\Hook\SkinCopyrightFooterMessageHook;
16use MediaWiki\Hook\SkinTemplateNavigation__UniversalHook;
17use MediaWiki\Hook\UploadForm_initialHook;
18use MediaWiki\Html\Html;
19use MediaWiki\Linker\Linker;
20use MediaWiki\Linker\LinkRenderer;
21use MediaWiki\MainConfigNames;
22use MediaWiki\Message\Message;
23use MediaWiki\Output\Hook\OutputPageBeforeHTMLHook;
24use MediaWiki\Output\OutputPage;
25use MediaWiki\Permissions\PermissionManager;
26use MediaWiki\Registration\ExtensionRegistry;
27use MediaWiki\ResourceLoader\Hook\ResourceLoaderRegisterModulesHook;
28use MediaWiki\ResourceLoader\ResourceLoader;
29use MediaWiki\Skin\Skin;
30use MediaWiki\Skin\SkinTemplate;
31use MediaWiki\SpecialPage\Hook\SpecialPageBeforeExecuteHook;
32use MediaWiki\SpecialPage\SpecialPage;
33use MediaWiki\Specials\SpecialUpload;
34use MediaWiki\Title\Title;
35use MediaWiki\User\Options\UserOptionsLookup;
36use MediaWiki\WikiMap\WikiMap;
37use MessageCache;
38use MessageLocalizer;
39use MobileContext;
40use Wikimedia\IPUtils;
41use Wikimedia\Message\MessageSpecifier;
42
43/**
44 * Hooks for WikimediaMessages extension
45 *
46 * @ingroup Extensions
47 */
48class Hooks implements
49    EditPageCopyrightWarningHook,
50    MessageCacheFetchOverridesHook,
51    OutputPageBeforeHTMLHook,
52    ResourceLoaderRegisterModulesHook,
53    SidebarBeforeOutputHook,
54    SkinAddFooterLinksHook,
55    SkinCopyrightFooterMessageHook,
56    SkinTemplateNavigation__UniversalHook,
57    SpecialPageBeforeExecuteHook,
58    UploadForm_initialHook
59{
60
61    public const CONSTRUCTOR_OPTIONS = [
62        MainConfigNames::DBname,
63        MainConfigNames::ForceUIMsgAsContentMsg,
64        'WikimediaMessagesLicensing',
65        MainConfigNames::LanguageCode,
66        MainConfigNames::RightsText,
67        MainConfigNames::RightsPage,
68        MainConfigNames::RightsUrl,
69    ];
70
71    public function __construct(
72        private readonly ExtensionRegistry $extensionRegistry,
73        private readonly LinkRenderer $linkRenderer,
74        private readonly PermissionManager $permissionManager,
75        private readonly ServiceOptions $options,
76        private readonly UserOptionsLookup $userOptionsLookup,
77        private readonly ?MobileContext $mobileContext = null,
78    ) {
79        $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
80    }
81
82    /**
83     * @param LinkRenderer $linkRenderer
84     * @param Config $mainConfig
85     * @param PermissionManager $permissionManager
86     * @param UserOptionsLookup $userOptionsLookup
87     * @param ?MobileContext $mobileContext
88     * @return self
89     */
90    public static function factory(
91        LinkRenderer $linkRenderer,
92        Config $mainConfig,
93        PermissionManager $permissionManager,
94        UserOptionsLookup $userOptionsLookup,
95        ?MobileContext $mobileContext = null,
96    ): self {
97        return new self(
98            ExtensionRegistry::getInstance(),
99            $linkRenderer,
100            $permissionManager,
101            new ServiceOptions( self::CONSTRUCTOR_OPTIONS, $mainConfig ),
102            $userOptionsLookup,
103            $mobileContext,
104        );
105    }
106
107    /**
108     * When core requests certain messages, change the key to a Wikimedia version.
109     *
110     * @see https://www.mediawiki.org/wiki/Manual:Hooks/MessageCacheFetchOverrides
111     * @param string[] &$keys
112     */
113    public function onMessageCacheFetchOverrides( array &$keys ): void {
114        global $wmgRealm, $wgNoticeProject;
115
116        static $keysToOverride = [
117            'acct_creation_throttle_hit',
118            'centralauth-contribs-locked',
119            // T216347
120            'centralauth-login-error-locked',
121            // T86741
122            'centralauth-groupname',
123            // T345549
124            'checkuser-api-useragent-clienthints-explanation',
125            'checkuser-toollinks',
126            // T380562
127            'checkuser-global-contributions-anon-tools',
128            'checkuser-global-contributions-ip-range-tools',
129            'checkuser-global-contributions-registered-user-tools',
130            // T327281
131            'checkuser-tempaccount-enable-preference-description',
132            // T380954
133            'checkuser-temporary-accounts-onboarding-dialog-temp-accounts-step-content',
134            'checkuser-temporary-accounts-onboarding-dialog-ip-info-step-content',
135            // T380955
136            'checkuser-temporary-accounts-onboarding-dialog-ip-reveal-step-content',
137            'checkuser-temporary-accounts-onboarding-dialog-ip-reveal-step-content-with-global-preferences',
138            // T375115
139            'checkuser-temporary-account-autorevoke-userright-reason',
140            // T380518
141            'checkuser-global-contributions-no-results-no-permissions',
142            // T362548
143            'checkuser-investigateblock-warning-ips-and-users-in-targets',
144            'createacct-helpusername',
145            'createacct-imgcaptcha-help',
146            // T139797
147            'delete-toobig',
148            // T385811
149            'vector-night-mode-issue-reporting-notice-url',
150            // T390662
151            'emailauth-login-help',
152            'feedback-termsofuse',
153            'globalblocking-blockedtext-ip',
154            'globalblocking-blockedtext-range',
155            'globalblocking-blockedtext-xff',
156            'globalblocking-blockedtext-user',
157            'globalblocking-blockedtext-autoblock',
158            'globalblocking-blockedtext-autoblock-xff',
159            'globalrenamequeue-email-body-approved',
160            'globalrenamequeue-email-body-rejected',
161            'interfaceadmin-info',
162            // T121639
163            'ipb-confirmhideuser',
164            'mwoauth-form-privacypolicy-link',
165            // T252375
166            'mobile-frontend-terms-url',
167            'mwoauthserver-invalid-user',
168            // T226059
169            'oathauth-step1-test',
170            // T189924, T406314
171            'oathauth-recovery-code-hint',
172            // T272412
173            'prefs-user-downloaddata-help-message',
174            'privacypage',
175            'sidebar',
176            // T140941
177            'sitematrix',
178            'sitematrix-others',
179            'sitematrix-summary',
180            'sulrenamewarning-usenew',
181            // T248367
182            'webauthn-module-description',
183            // T248367
184            'webauthn-ui-login-prompt',
185            // T218160
186            'log-action-filter-usermerge',
187            'log-action-filter-usermerge-mergeuser',
188            'log-action-filter-usermerge-deleteuser',
189            'notification-body-oathauth-disable-other',
190            'oathauth-notifications-disable-helplink',
191            // T307493, T375090
192            'ipinfo-help-text',
193            'ipinfo-infobox-use-terms',
194            'ipinfo-preference-use-agreement',
195            'similareditors-error-default',
196            // T348926
197            'jsonconfig-license-copyrightwarning',
198            'jsonconfig-license-copyrightwarning-license-unset',
199            'jsonconfig-license-notice',
200            'jsonconfig-license-notice-license-unset',
201            // T340115
202            'campaignevents-edit-field-clickwrap-checkbox-label',
203            // T322209
204            'campaignevents-edit-form-questions-pii-notice',
205            // T357869
206            'pt-movepage-page-count-limit',
207            'skin-minerva-donate-banner-message',
208            'skin-minerva-donate-banner-subtitle',
209            'skin-minerva-donate-banner-gif',
210            'skin-minerva-donate-banner-reduced-motion',
211            'skin-minerva-donate-banner-url',
212            'namespaceinfo-description-ns470',
213            // T395565
214            'pvi-month-count-value',
215            // T399742
216            'emailauth-accountrecovery-intro',
217            'emailauth-accountrecovery-registeredemail-label',
218        ];
219
220        static $allbutmetawikikeys = [
221            // T221526
222            'apierror-urlshortener-disabled',
223            // T230253
224            'apierror-urlshortener-permissiondenied',
225            // T331743
226            'centralauth-admin-log-otherwiki',
227            // T230253
228            'urlshortener-badaccessgroups',
229            // T221526
230            'urlshortener-disabled',
231        ];
232
233        // Temporarily override grouppage-suppress to grouppage-oversight,
234        // to avoid breaking links. See T112147.
235        $keys['grouppage-suppress'] = 'grouppage-oversight';
236
237        if ( $wmgRealm === 'labs' ) {
238            $keys['privacypage'] = 'wikimedia-privacypage-labs';
239        }
240
241        $languageCode = $this->options->get( MainConfigNames::LanguageCode );
242
243        $transformationCallback = static function ( string $key, MessageCache $cache ) use ( $languageCode ): string {
244            $transformedKey = "wikimedia-$key";
245
246            // MessageCache uses ucfirst if ord( key ) is < 128, which is true of all
247            // of the above.  Revisit if non-ASCII keys are used.
248            $ucKey = ucfirst( $key );
249
250            if (
251                /*
252                 * Override order:
253                 * 1. If the MediaWiki:$ucKey page exists, use the key unprefixed
254                 * (in all languages) with normal fallback order.  Specific
255                 * language pages (MediaWiki:$ucKey/xy) are not checked when
256                 * deciding which key to use, but are still used if applicable
257                 * after the key is decided.
258                 *
259                 * 2. Otherwise, use the prefixed key with normal fallback order
260                 * (including MediaWiki pages if they exist).
261                 */
262                $cache->getMsgFromNamespace( $ucKey, $languageCode ) === false
263            ) {
264                return $transformedKey;
265            }
266
267            return $key;
268        };
269
270        foreach ( $keysToOverride as $key ) {
271            $keys[$key] = $transformationCallback;
272        }
273
274        if ( $this->options->get( MainConfigNames::DBname ) !== 'metawiki' ) {
275            foreach ( $allbutmetawikikeys as $key ) {
276                $keys[$key] = $transformationCallback;
277            }
278        }
279
280        $licensing = $this->options->get( 'WikimediaMessagesLicensing' );
281        $rightsText = $this->options->get( MainConfigNames::RightsText );
282
283        switch ( $licensing ) {
284            case 'mediawiki':
285                $keys['mobile-frontend-license-links'] = 'mediawiki.org-mobile-license-links';
286                break;
287            case 'wikidata':
288                $keys['mobile-frontend-license-links'] = 'wikidata-mobile-license-links';
289                break;
290            case 'wikifunctions':
291                $keys['mobile-frontend-license-links'] = 'wikifunctions-mobile-license-links';
292                break;
293            case 'commons':
294            case 'standard':
295                $keys['mobile-frontend-license-links'] = 'wikimedia-mobile-license-links';
296                break;
297            case 'wikinews':
298                // This is necessary because MobileFrontend doesn't always display the license based on
299                // config settings (T296791)
300                $licenseMap = [
301                    'Creative Commons Attribution 2.5' => 'wikinews-mobile-license-links',
302                    'Creative Commons Attribution 3.0' => 'wikinews-mobile-license-links-ccby30',
303                    'Creative Commons Attribution 4.0' => 'wikinews-mobile-license-links-ccby40',
304                    'Creative Commons Attribution-Share Alike 4.0' => 'wikinews-mobile-license-links-ccbysa40',
305                ];
306                if ( !isset( $licenseMap[$rightsText] ) ) {
307                    throw new ConfigException( "You must define a license message for $rightsText" );
308                }
309                $keys['mobile-frontend-license-links'] = $licenseMap[$rightsText];
310                break;
311            default:
312                throw new ConfigException( "Unknown value for WikimediaMessagesLicensing: '$licensing'" );
313        }
314
315        $keys['mainpage-title-loggedin'] = function ( string $key ): string {
316            return ( $this->mobileContext && $this->mobileContext->shouldDisplayMobileView() ) ?
317                'wikimedia-mobile-mainpage-title-loggedin' : $key;
318        };
319
320        // T391026: Use a generic message on sister projects like Wiktionary or Commons.
321        // On Wikipedia projects (determined by wgNoticeProject),
322        // keep the Wikipedia-specific message
323        $keys['skin-minerva-donate-banner-subtitle'] = (
324            $wgNoticeProject === 'wikipedia'
325        )
326            ? 'wikimedia-skin-minerva-donate-banner-subtitle'
327            : 'wikimedia-skin-minerva-donate-banner-subtitle-generic';
328    }
329
330    private function getShortRightsLink(): string {
331        $rightsText = $this->options->get( MainConfigNames::RightsText );
332        $rightsPage = $this->options->get( MainConfigNames::RightsPage );
333        $rightsUrl = $this->options->get( MainConfigNames::RightsUrl );
334        $commonLicenses = [
335            'Creative Commons Attribution-Share Alike 4.0' => 'CC BY-SA 4.0',
336            'Creative Commons Attribution-Share Alike 3.0' => 'CC BY-SA 3.0',
337            'Creative Commons Attribution 3.0' => 'CC BY 3.0',
338            'Creative Commons Attribution 2.5' => 'CC BY 2.5',
339        ];
340        if ( isset( $commonLicenses[$rightsText] ) ) {
341            $rightsText = $commonLicenses[$rightsText];
342        }
343        if ( $rightsPage ) {
344            $title = Title::newFromText( $rightsPage );
345            $link = $this->linkRenderer->makeKnownLink( $title, new HtmlArmor( $rightsText ), [] );
346        } elseif ( $rightsUrl ) {
347            $link = Linker::makeExternalLink( $rightsUrl, $rightsText, true, '', [] );
348        } else {
349            $link = $rightsText;
350        }
351        return $link;
352    }
353
354    /**
355     * Override for copyright message in skin footer.
356     *
357     * @see https://www.mediawiki.org/wiki/Manual:Hooks/SkinCopyrightFooterMessage
358     *
359     * @param Title $title
360     * @param string $type
361     * @param MessageSpecifier &$msgSpec
362     */
363    public function onSkinCopyrightFooterMessage( $title, $type, &$msgSpec ) {
364        if ( $type === 'history' ) {
365            return;
366        }
367
368        $licensing = $this->options->get( 'WikimediaMessagesLicensing' );
369        $isMobile = $this->mobileContext && $this->mobileContext->shouldDisplayMobileView();
370
371        switch ( $licensing ) {
372            case 'wikidata':
373                // Wikidata is licensed under CC-BY-SA 4.0 only, no GFDL. (Also, the data is under CC0.)
374                $msgSpec = Message::newFromSpecifier( 'wikidata-copyright-footer' );
375                break;
376            case 'mediawiki':
377                // MediaWiki.org has a special licence for the Help: namespace.
378                $msgSpec = Message::newFromSpecifier( 'mediawiki.org-copyright-footer' );
379                break;
380            case 'commons':
381                // Commons has a special licence for the structured data.
382                // TODO: Should we also mention the special Data: namespace?
383                $msgSpec = Message::newFromSpecifier( 'wikimedia-commons-copyright-footer' );
384                break;
385            case 'standard':
386                // Almost all Wikimedia wikis using CC-BY-SA 4.0 are also dual-licensed under GFDL.
387                $msgSpec = $isMobile
388                    ? Message::newFromSpecifier( 'mobile-frontend-copyright' )->rawParams( $this->getShortRightsLink() )
389                    : Message::newFromSpecifier( 'wikimedia-copyright-footer' );
390                break;
391            case 'wikinews':
392                // Use the default MediaWiki message. (It's overridden locally on most Wikinewses.)
393                $msgSpec = $isMobile
394                    ? Message::newFromSpecifier( 'mobile-frontend-copyright' )->rawParams( $this->getShortRightsLink() )
395                    : $msgSpec;
396                break;
397            case 'wikifunctions':
398                // Wikifunctions like Wikidata is licensed under CC-BY-SA 4.0 only, no GFDL. The data is
399                // under CC0. The code is under Apache 2.0.
400                $msgSpec = Message::newFromSpecifier( 'wikifunctions-site-footer-copyright-footer' );
401                break;
402            default:
403                throw new ConfigException( "Unknown value for WikimediaMessagesLicensing: '$licensing'" );
404        }
405    }
406
407    /**
408     * Override for copyright message on edit page.
409     *
410     * @see https://www.mediawiki.org/wiki/Manual:Hooks/EditPageCopyrightWarning
411     *
412     * @param Title $title
413     * @param array &$msg
414     */
415    public function onEditPageCopyrightWarning( $title, &$msg ) {
416        $licensing = $this->options->get( 'WikimediaMessagesLicensing' );
417
418        switch ( $licensing ) {
419            case 'wikidata':
420            case 'wikifunctions':
421                // Wikidata and Wikifunctions are licensed under CC-BY-SA 4.0 only, no GFDL.
422                $msg = [ 'wikimedia-copyrightwarning-ccbysa40only' ];
423                break;
424            case 'mediawiki':
425                // MediaWiki.org pages are dual-licensed under CC-BY-SA 4.0 and GFDL, except for the Help: namespace.
426                $msg = [ 'mediawiki.org-copyrightwarning' ];
427                break;
428            case 'commons':
429            case 'standard':
430                // Almost all Wikimedia wikis using CC-BY-SA 4.0 are also dual-licensed under GFDL.
431                $msg = [ 'wikimedia-copyrightwarning' ];
432                break;
433            case 'wikinews':
434                // Use the default MediaWiki message. (It's overridden locally on most Wikinewses.)
435                break;
436            default:
437                throw new ConfigException( "Unknown value for WikimediaMessagesLicensing: '$licensing'" );
438        }
439    }
440
441    /**
442     * Override for copyright messages (DiscussionTools extension).
443     *
444     * @param array &$messages
445     * @param MessageLocalizer $context
446     * @param Config $config
447     */
448    public static function onDiscussionToolsTermsOfUseMessages(
449        array &$messages, MessageLocalizer $context, Config $config
450    ) {
451        $licensing = $config->get( 'WikimediaMessagesLicensing' );
452
453        switch ( $licensing ) {
454            case 'wikidata':
455            case 'wikifunctions':
456                // Do not use $wgRightsText or $wgRightsPage, as they are customized for the API (T112606).
457                $rightsUrl = $config->get( 'RightsUrl' );
458                $rightsText = 'Creative Commons Attribution-Share Alike 4.0';
459                $links = [ "[$rightsUrl $rightsText]", 1 ];
460                break;
461            case 'wikinews':
462                // Add the license name to the terms-of-use message
463                $rightsUrl = $config->get( 'RightsUrl' );
464                $rightsText = $config->get( 'RightsText' );
465                $links = [ "[$rightsUrl $rightsText]", 1 ];
466                break;
467            case 'commons':
468            case 'mediawiki':
469            case 'standard':
470                // Add the license names to the terms-of-use message - dual-licensed wikis
471                $links = [ $context->msg( 'wikimedia-license-links' )->plain(), 2 ];
472                break;
473            default:
474                throw new ConfigException( "Unknown value for WikimediaMessagesLicensing: '$licensing'" );
475        }
476
477        $messages['reply'] = array_merge( [ 'wikimedia-discussiontools-replywidget-terms-click',
478            $context->msg( 'discussiontools-replywidget-reply' )->text() ], $links );
479        $messages['newtopic'] = array_merge( [ 'wikimedia-discussiontools-replywidget-terms-click',
480            $context->msg( 'discussiontools-replywidget-newtopic' )->text() ], $links );
481    }
482
483    /**
484     * Override for copyright messages (Flow extension).
485     *
486     * @param array &$messages
487     * @param MessageLocalizer $context
488     * @param Config $config
489     */
490    public static function onFlowTermsOfUseMessages(
491        array &$messages, MessageLocalizer $context, Config $config
492    ) {
493        $licensing = $config->get( 'WikimediaMessagesLicensing' );
494
495        switch ( $licensing ) {
496            case 'wikidata':
497            case 'wikifunctions':
498                // Do not use $wgRightsText or $wgRightsPage, as they are customized for the API (T112606).
499                $rightsUrl = $config->get( 'RightsUrl' );
500                $rightsText = 'Creative Commons Attribution-Share Alike 4.0';
501                $links = [ "[$rightsUrl $rightsText]", 1 ];
502                break;
503            case 'wikinews':
504                // Add the license name to the terms-of-use message
505                $rightsUrl = $config->get( 'RightsUrl' );
506                $rightsText = $config->get( 'RightsText' );
507                $links = [ "[$rightsUrl $rightsText]", 1 ];
508                break;
509            case 'commons':
510            case 'mediawiki':
511            case 'standard':
512                // Add the license names to the terms-of-use message - dual-licensed wikis
513                $links = [ $context->msg( 'wikimedia-license-links' )->plain(), 2 ];
514                break;
515            default:
516                throw new ConfigException( "Unknown value for WikimediaMessagesLicensing: '$licensing'" );
517        }
518
519        $messages['edit'] = array_merge( [ 'wikimedia-flow-terms-of-use-edit' ], $links );
520        $messages['lock-topic'] = array_merge( [ 'wikimedia-flow-terms-of-use-lock-topic' ], $links );
521        $messages['new-topic'] = array_merge( [ 'wikimedia-flow-terms-of-use-new-topic' ], $links );
522        $messages['reply'] = array_merge( [ 'wikimedia-flow-terms-of-use-reply' ], $links );
523        $messages['summarize'] = array_merge( [ 'wikimedia-flow-terms-of-use-summarize' ], $links );
524        $messages['unlock-topic'] = array_merge( [ 'wikimedia-flow-terms-of-use-unlock-topic' ], $links );
525    }
526
527    /**
528     * Add links to the footer of every page:
529     *   - "Developers" (T35464),
530     *   - "Statistics" (T235803), and
531     *   - "Cookie statement" (T124366)
532     *
533     * @see https://www.mediawiki.org/wiki/Manual:Hooks/SkinAddFooterLinks
534     *
535     * @param Skin $skin
536     * @param string $key
537     * @param array &$footerLinks
538     */
539    public function onSkinAddFooterLinks( Skin $skin, string $key, array &$footerLinks ) {
540        if ( $key !== 'places' ) {
541            return;
542        }
543        $devDestination = Skin::makeInternalOrExternalUrl(
544            $skin->msg( 'wikimedia-developers-url' )->inContentLanguage()->text()
545        );
546        $footerLinks['developers'] = Html::element(
547            'a',
548            [ 'href' => $devDestination ],
549            $skin->msg( 'wikimedia-developers' )->text()
550        );
551
552        // T401547: Instead of just reading $wgServerName which is overridden when on the shared
553        // domain, let's get the current wiki's ID from the shared domain perspective and extract
554        // the hostname from there.
555        $wiki = WikiMap::getWiki( WikiMap::getCurrentWikiId() );
556        if ( !$wiki ) {
557            // Fallback to the default server name of the current domain
558            $serverName = $skin->getConfig()->get( MainConfigNames::ServerName );
559        } else {
560            $serverName = $wiki->getDisplayName();
561        }
562
563        $statsDestination = Skin::makeInternalOrExternalUrl(
564            $skin->msg( 'wikimedia-statslink-url', $serverName )->inContentLanguage()->text()
565        );
566        $footerLinks['statslink'] = Html::element(
567            'a',
568            [ 'href' => $statsDestination ],
569            $skin->msg( 'wikimedia-statslink' )->text()
570        );
571
572        $cookieDestination = Skin::makeInternalOrExternalUrl(
573            $skin->msg( 'wikimedia-cookiestatement-page' )->inContentLanguage()->text()
574        );
575        $footerLinks['cookiestatement'] = Html::element(
576            'a',
577            [ 'href' => $cookieDestination ],
578            $skin->msg( 'wikimedia-cookiestatement' )->text()
579        );
580    }
581
582    /**
583     * Change which message is shown when TorBlock triggers (TorBlock extension)
584     *
585     * @todo FIXME: Should have a specific message for WMF projects (T44231)
586     *
587     * @todo once TorBlock updates to use hook interfaces that can be implemented,
588     * convert to using this class as a hook handler and make non-static with DI
589     *
590     * @param string &$msg The message key
591     */
592    public static function onTorBlockBlockedMsg( &$msg ) {
593        $msg = 'wikimedia-torblock-blocked';
594    }
595
596    /**
597     * Require the creation of MediaWiki:Licenses to enable uploading.
598     * This should prevent a lot of uploading without licenses on small wikis;
599     * some or many of the small WMF wikis do not have any license options,
600     * which is really needed for our copyright policy.
601     *
602     * Do not require it when licenses is in $wgForceUIMsgAsContentMsg,
603     * to prevent checking each subpage of MediaWiki:Licenses.
604     *
605     * @param SpecialUpload $upload
606     * @throws ErrorPageError
607     */
608    public function onUploadForm_initial( $upload ) {
609        $forceUIMsgAsContentMsg = $this->options->get( MainConfigNames::ForceUIMsgAsContentMsg );
610
611        // TODO inject something to replace use of wfMessage
612        if ( !in_array( 'licenses', $forceUIMsgAsContentMsg )
613            && wfMessage( 'licenses' )->inContentLanguage()->isDisabled()
614        ) {
615            throw new ErrorPageError( 'uploaddisabled', 'wikimedia-upload-nolicenses' );
616        }
617    }
618
619    /**
620     * Override `$wgGrammarForms` for Wikimedia sites as a more convenient form
621     * than setting in InitialiseSettings.php. Initial version was compiled from
622     * then-current Wikimedia configuration and contents of LanguageXx.php.
623     */
624    public static function onRegistration() {
625        global $wgGrammarForms;
626
627        $wgGrammarForms['ang'] = [
628            // accusative
629            'wrēgendlīc' => [
630                'Wikipǣdia' => 'Wikipǣdie',
631                'Wikiwordbōc' => 'Wikiwordbōc',
632            ],
633            // genitive
634            'geāgniendlīc' => [
635                'Wikipǣdia' => 'Wikipǣdie',
636                'Wikiwordbōc' => 'Wikiwordbēc',
637            ],
638            // dative
639            'forgifendlīc' => [
640                'Wikipǣdia' => 'Wikipǣdie',
641                'Wikiwordbōc' => 'Wikiwordbēc',
642            ],
643            // instrumental
644            'tōllīc' => [
645                'Wikipǣdia' => 'Wikipǣdie',
646                'Wikiwordbōc' => 'Wikiwordbēc',
647            ],
648        ];
649
650        $wgGrammarForms['be'] = [
651            // genitive
652            'родны' => [
653                'Віківіды'    => 'Віківідаў',
654                'Вікіданыя'   => 'Вікіданых',
655                'Вікікнігі'   => 'Вікікніг',
656                'Вікікрыніцы' => 'Вікікрыніц',
657                'Вікінавіны'  => 'Вікінавін',
658                'Вікіслоўнік' => 'Вікіслоўніка',
659                'Вікіпедыя'   => 'Вікіпедыі',
660            ],
661            // accusative
662            'вінавальны' => [
663                'Вікіпедыя'   => 'Вікіпедыю',
664            ],
665            // prepositional
666            'месны' => [
667                'Віківіды'    => 'Віківідах',
668                'Вікіданыя'   => 'Вікіданых',
669                'Вікікнігі'   => 'Вікікнігах',
670                'Вікікрыніцы' => 'Вікікрыніцах',
671                'Вікінавіны'  => 'Вікінавінах',
672                'Вікіслоўнік' => 'Вікіслоўніку',
673                'Вікіпедыя'   => 'Вікіпедыі',
674            ],
675        ];
676
677        $wgGrammarForms['be-tarask'] = [
678            // genitive
679            'родны' => [
680                'Віківіды'    => 'Віківідаў',
681                'Вікізьвесткі' => 'Вікізьвестак',
682                'Вікікнігі'   => 'Вікікніг',
683                'Вікікрыніцы' => 'Вікікрыніц',
684                'Вікімэдыя'   => 'Вікімэдыі',
685                'Вікінавіны'  => 'Вікінавін',
686                'Вікіпэдыя'   => 'Вікіпэдыі',
687                'Вікіслоўнік' => 'Вікіслоўніка',
688                'Вікісховішча' => 'Вікісховішча',
689                'Фундацыя «Вікімэдыя»' => 'Фундацыі «Вікімэдыя»',
690            ],
691            // dative
692            'давальны' => [
693                'Віківіды'    => 'Віківідам',
694                'Вікізьвесткі' => 'Вікізьвесткам',
695                'Вікікнігі'   => 'Вікікнігам',
696                'Вікікрыніцы' => 'Вікікрыніцам',
697                'Вікімэдыя'   => 'Вікімэдыі',
698                'Вікінавіны'  => 'Вікінавінам',
699                'Вікіпэдыя'   => 'Вікіпэдыі',
700                'Вікіслоўнік' => 'Вікіслоўніку',
701                'Вікісховішча' => 'Вікісховішчу',
702                'Фундацыя «Вікімэдыя»' => 'Фундацыі «Вікімэдыя»',
703            ],
704            // accusative
705            'вінавальны' => [
706                'Віківіды'    => 'Віківіды',
707                'Вікізьвесткі' => 'Вікізьвесті',
708                'Вікікнігі'   => 'Вікікнігі',
709                'Вікікрыніцы' => 'Вікікрыніцы',
710                'Вікімэдыя'   => 'Вікімэдыю',
711                'Вікінавіны'  => 'Вікінавіны',
712                'Вікіпэдыя'   => 'Вікіпэдыю',
713                'Вікіслоўнік' => 'Вікіслоўнік',
714                'Вікісховішча' => 'Вікісховішча',
715                'Фундацыя «Вікімэдыя»' => 'Фундацыю «Вікімэдыя»',
716            ],
717            // instrumental
718            'творны' => [
719                'Віківіды'    => 'Віківідамі',
720                'Вікізьвесткі' => 'Вікізьвесткамі',
721                'Вікікнігі'   => 'Вікікнігамі',
722                'Вікікрыніцы' => 'Вікікрыніцамі',
723                'Вікімэдыя'   => 'Вікімэдыяй',
724                'Вікінавіны'  => 'Вікінавінамі',
725                'Вікіпэдыя'   => 'Вікіпэдыяй',
726                'Вікіслоўнік' => 'Вікіслоўнікам',
727                'Вікісховішча' => 'Вікісховішчам',
728                'Фундацыя «Вікімэдыя»' => 'Фундацыяй «Вікімэдыя»',
729            ],
730            // prepositional
731            'месны' => [
732                'Віківіды'    => 'Віківідах',
733                'Вікізьвесткі' => 'Вікізьвестках',
734                'Вікікнігі'   => 'Вікікнігах',
735                'Вікікрыніцы' => 'Вікікрыніцах',
736                'Вікімэдыя'   => 'Вікімэдыі',
737                'Вікінавіны'  => 'Вікінавінах',
738                'Вікіпэдыя'   => 'Вікіпэдыі',
739                'Вікіслоўнік' => 'Вікіслоўніку',
740                'Вікісховішча' => 'Вікісховішчы',
741                'Фундацыя «Вікімэдыя»' => 'Фундацыі «Вікімэдыя»',
742            ],
743        ];
744
745        $wgGrammarForms['bs'] = [
746            // genitive
747            'genitiv' => [
748                'Vikirječnik' => 'Wikirječnika',
749                'Wikicitati'  => 'Wikicitata',
750                'Wikiizvor'   => 'Wikiizvora',
751                'Wikiknjige'  => 'Wikiknjiga',
752                'Wikipedia'   => 'Wikipedije',
753                'Wikipodaci'  => 'Wikipodataka',
754                'Wikimedia Commons' => 'Wikimedia Commonsa',
755            ],
756            // dative
757            'dativ' => [
758                'Vikirječnik' => 'Wikirječniku',
759                'Wikicitati'  => 'Wikicitatima',
760                'Wikiizvor'   => 'Wikiizvoru',
761                'Wikiknjige'  => 'Wikiknjigama',
762                'Wikipedia'   => 'Wikipediji',
763                'Wikipodaci'  => 'Wikipodacima',
764                'Wikivijesti' => 'Wikivijestima',
765                'Wikimedia Commons' => 'Wikimedia Commonsu',
766            ],
767            // accusative
768            'akuzativ' => [
769                'Vikirječnik' => 'Wikirječnik',
770                'Wikicitati'  => 'Wikicitate',
771                'Wikiizvor'   => 'Wikiizvora',
772                'Wikipedia'   => 'Wikipediju',
773                'Wikipodaci'  => 'Wikipodatke',
774            ],
775            // vocative
776            'vokativ' => [
777                'Vikirječnik' => 'Wikirječniče',
778                'Wikiizvor'   => 'Wikizivoru',
779                'Wikipedia'   => 'Wikipedijo',
780                'Wikimedia Commons' => 'Wikimedia Commonse',
781            ],
782            // instrumental
783            'instrumental' => [
784                'Vikirječnik' => 'Wikirječnikom',
785                'Wikicitati'  => 'Wikicitatima',
786                'Wikiizvor'   => 'Wikiizvorom',
787                'Wikiknjige'  => 'Wikiknjigama',
788                // T130141
789                'Wikipedia'   => 'Wikipedijom',
790                'Wikipodaci'  => 'Wikipodacima',
791                'Wikivijesti' => 'Wikivijestima',
792                'Wikimedia Commons' => 'Wikimedia Commonsom',
793            ],
794            // locative
795            'lokativ' => [
796                'Vikirječnik' => 'Wikirječniku',
797                'Wikicitati'  => 'Wikicitatima',
798                'Wikiizvor'   => 'Wikiizvoru',
799                'Wikiknjige'  => 'Wikiknjigama',
800                'Wikipedia'   => 'Wikipediji',
801                'Wikipodaci'  => 'Wikipodacima',
802                'Wikivijesti' => 'Wikivijestima',
803                'Wikimedia Commons' => 'Wikimedia Commonsu',
804            ],
805        ];
806
807        $wgGrammarForms['cs'] = [
808            // only forms different than default/given
809            '1sg' => [
810                'Wikibooks'   => 'Wikiknihy',
811                'Wikifunctions' => 'Wikifunkce',
812                'Wikinews'    => 'Wikizprávy',
813                'Wikipedia'   => 'Wikipedie',
814                'Wikiquote'   => 'Wikicitáty',
815                'Wikisource'  => 'Wikizdroje',
816                'Wikispecies' => 'Wikidruhy',
817                'Wikiversity' => 'Wikiverzita',
818                'Wikivoyage'  => 'Wikicesty',
819                'Wiktionary'  => 'Wikislovník',
820            ],
821            '2sg' => [
822                'uživatel'    => 'uživatele',
823                'Wikibooks'   => 'Wikiknih',
824                'Wikidata'    => 'Wikidat',
825                'Wikifunctions' => 'Wikifunkcí',
826                'Wikinews'    => 'Wikizpráv',
827                'Wikipedia'   => 'Wikipedie',
828                'Wikiquote'   => 'Wikicitátů',
829                'Wikisource'  => 'Wikizdrojů',
830                'Wikispecies' => 'Wikidruhů',
831                'Wikiversity' => 'Wikiverzity',
832                'Wikivoyage'  => 'Wikicest',
833                'Wiktionary'  => 'Wikislovníku',
834                'Wikicesty'   => 'Wikicest',
835                'Wikicitáty'  => 'Wikicitátů',
836                'Wikidruhy'   => 'Wikidruhů',
837                'Wikifunkce'  => 'Wikifunkcí',
838                'Wikiknihy'   => 'Wikiknih',
839                'Wikislovník' => 'Wikislovníku',
840                'Wikiverzita' => 'Wikiverzity',
841                'Wikizdroje'  => 'Wikizdrojů',
842                'Wikizprávy'  => 'Wikizpráv',
843            ],
844            '3sg' => [
845                'uživatel'    => 'uživateli',
846                'Wikibooks'   => 'Wikiknihám',
847                'Wikidata'    => 'Wikidatům',
848                'Wikifunctions' => 'Wikifunkcím',
849                'Wikinews'    => 'Wikizprávám',
850                'Wikipedia'   => 'Wikipedii',
851                'Wikiquote'   => 'Wikicitátům',
852                'Wikisource'  => 'Wikizdrojům',
853                'Wikispecies' => 'Wikidruhům',
854                'Wikiversity' => 'Wikiverzitě',
855                'Wikivoyage'  => 'Wikicestám',
856                'Wiktionary'  => 'Wikislovníku',
857                'Wikicesty'   => 'Wikicestám',
858                'Wikicitáty'  => 'Wikicitátům',
859                'Wikidruhy'   => 'Wikidruhům',
860                'Wikifunkce'  => 'Wikifunkcím',
861                'Wikiknihy'   => 'Wikiknihám',
862                'Wikipedie'   => 'Wikipedii',
863                'Wikislovník' => 'Wikislovníku',
864                'Wikiverzita' => 'Wikiverzitě',
865                'Wikizdroje'  => 'Wikizdrojům',
866                'Wikizprávy'  => 'Wikizprávám',
867            ],
868            '4sg' => [
869                'uživatel'    => 'uživatele',
870                'Wikibooks'   => 'Wikiknihy',
871                'Wikifunctions' => 'Wikifunkce',
872                'Wikinews'    => 'Wikizprávy',
873                'Wikipedia'   => 'Wikipedii',
874                'Wikiquote'   => 'Wikicitáty',
875                'Wikisource'  => 'Wikizdroje',
876                'Wikispecies' => 'Wikidruhy',
877                'Wikiversity' => 'Wikiverzitu',
878                'Wikivoyage'  => 'Wikicesty',
879                'Wiktionary'  => 'Wikislovník',
880                'Wikipedie'   => 'Wikipedii',
881                'Wikiverzita' => 'Wikiverzitu',
882            ],
883            '5sg' => [
884                'uživatel'    => 'uživateli',
885                'Wikibooks'   => 'Wikiknihy',
886                'Wikifunctions' => 'Wikifunkce',
887                'Wikinews'    => 'Wikizprávy',
888                'Wikipedia'   => 'Wikipedie',
889                'Wikiquote'   => 'Wikicitáty',
890                'Wikisource'  => 'Wikizdroje',
891                'Wikispecies' => 'Wikidruhy',
892                'Wikiversity' => 'Wikiverzito',
893                'Wikivoyage'  => 'Wikicesty',
894                'Wiktionary'  => 'Wikislovníku',
895                'Wikislovník' => 'Wikislovníku',
896                'Wikiverzita' => 'Wikiverzito',
897            ],
898            '6sg' => [
899                'uživatel'    => 'uživateli',
900                'Wikibooks'   => 'Wikiknihách',
901                'Wikidata'    => 'Wikidatech',
902                'Wikifunctions' => 'Wikifunkcích',
903                'Wikinews'    => 'Wikizprávách',
904                'Wikipedia'   => 'Wikipedii',
905                'Wikiquote'   => 'Wikicitátech',
906                'Wikisource'  => 'Wikizdrojích',
907                'Wikispecies' => 'Wikidruzích',
908                'Wikiversity' => 'Wikiverzitě',
909                'Wikivoyage'  => 'Wikicestách',
910                'Wiktionary'  => 'Wikislovníku',
911                'Wikicesty'   => 'Wikicestách',
912                'Wikicitáty'  => 'Wikicitátech',
913                'Wikidruhy'   => 'Wikidruzích',
914                'Wikifunkce'  => 'Wikifunkcích',
915                'Wikiknihy'   => 'Wikiknihách',
916                'Wikipedie'   => 'Wikipedii',
917                'Wikislovník' => 'Wikislovníku',
918                'Wikiverzita' => 'Wikiverzitě',
919                'Wikizdroje'  => 'Wikizdrojích',
920                'Wikizprávy'  => 'Wikizprávách',
921            ],
922            '7sg' => [
923                'uživatel'    => 'uživatelem',
924                'Wikibooks'   => 'Wikiknihami',
925                'Wikidata'    => 'Wikidaty',
926                'Wikifunctions' => 'Wikifunkcemi',
927                'Wikinews'    => 'Wikizprávami',
928                'Wikipedia'   => 'Wikipedií',
929                'Wikiquote'   => 'Wikicitáty',
930                'Wikisource'  => 'Wikizdroji',
931                'Wikispecies' => 'Wikidruhy',
932                'Wikiversity' => 'Wikiverzitou',
933                'Wikivoyage'  => 'Wikicestami',
934                'Wiktionary'  => 'Wikislovníkem',
935                'Wikicesty'   => 'Wikicestami',
936                'Wikifunkce'  => 'Wikifunkcemi',
937                'Wikiknihy'   => 'Wikiknihami',
938                'Wikipedie'   => 'Wikipedií',
939                'Wikislovník' => 'Wikislovníkem',
940                'Wikiverzita' => 'Wikiverzitou',
941                'Wikizdroje'  => 'Wikizdroji',
942                'Wikizprávy'  => 'Wikizprávami',
943            ],
944            '1pl' => [
945                'uživatel'    => 'uživatelé',
946                'Wikibooks'   => 'Wikiknihy',
947                'Wikifunctions' => 'Wikifunkce',
948                'Wikinews'    => 'Wikizprávy',
949                'Wikipedia'   => 'Wikipedie',
950                'Wikiquote'   => 'Wikicitáty',
951                'Wikisource'  => 'Wikizdroje',
952                'Wikispecies' => 'Wikidruhy',
953                'Wikiversity' => 'Wikiverzity',
954                'Wikivoyage'  => 'Wikicesty',
955                'Wiktionary'  => 'Wikislovníky',
956                'Wikislovník' => 'Wikislovníky',
957                'Wikiverzita' => 'Wikiverzity',
958            ],
959            '2pl' => [
960                'uživatel'    => 'uživatelů',
961                'Wikibooks'   => 'Wikiknih',
962                'Wikidata'    => 'Wikidat',
963                'Wikifunctions' => 'Wikifunkcí',
964                'Wikinews'    => 'Wikizpráv',
965                'Wikipedia'   => 'Wikipedií',
966                'Wikiquote'   => 'Wikicitátů',
967                'Wikisource'  => 'Wikizdrojů',
968                'Wikispecies' => 'Wikidruhů',
969                'Wikiversity' => 'Wikiverzit',
970                'Wikivoyage'  => 'Wikicest',
971                'Wiktionary'  => 'Wikislovníků',
972                'Wikicesty'   => 'Wikicest',
973                'Wikicitáty'  => 'Wikicitátů',
974                'Wikidruhy'   => 'Wikidruhů',
975                'Wikifunkce'  => 'Wikifunkcí',
976                'Wikiknihy'   => 'Wikiknih',
977                'Wikipedie'   => 'Wikipedií',
978                'Wikislovník' => 'Wikislovníků',
979                'Wikiverzita' => 'Wikiverzit',
980                'Wikizdroje'  => 'Wikizdrojů',
981                'Wikizprávy'  => 'Wikizpráv',
982            ],
983            '3pl' => [
984                'uživatel'    => 'uživatelům',
985                'Wikibooks'   => 'Wikiknihám',
986                'Wikidata'    => 'Wikidatům',
987                'Wikifunctions' => 'Wikifunkcím',
988                'Wikinews'    => 'Wikizprávám',
989                'Wikipedia'   => 'Wikipediím',
990                'Wikiquote'   => 'Wikicitátům',
991                'Wikisource'  => 'Wikizdrojům',
992                'Wikispecies' => 'Wikidruhům',
993                'Wikiversity' => 'Wikiverzitám',
994                'Wikivoyage'  => 'Wikicestám',
995                'Wiktionary'  => 'Wikislovníkům',
996                'Wikicesty'   => 'Wikicestám',
997                'Wikicitáty'  => 'Wikicitátům',
998                'Wikidruhy'   => 'Wikidruhům',
999                'Wikifunkce'  => 'Wikifunkcím',
1000                'Wikiknihy'   => 'Wikiknihám',
1001                'Wikipedie'   => 'Wikipediím',
1002                'Wikislovník' => 'Wikislovníkům',
1003                'Wikiverzita' => 'Wikiverzitám',
1004                'Wikizdroje'  => 'Wikizdrojům',
1005                'Wikizprávy'  => 'Wikizprávám',
1006            ],
1007            '4pl' => [
1008                'uživatel'    => 'uživatele',
1009                'Wikibooks'   => 'Wikiknihy',
1010                'Wikifunctions' => 'Wikifunkce',
1011                'Wikinews'    => 'Wikizprávy',
1012                'Wikipedia'   => 'Wikipedie',
1013                'Wikiquote'   => 'Wikicitáty',
1014                'Wikisource'  => 'Wikizdroje',
1015                'Wikispecies' => 'Wikidruhy',
1016                'Wikiversity' => 'Wikiverzity',
1017                'Wikivoyage'  => 'Wikicesty',
1018                'Wiktionary'  => 'Wikislovníky',
1019                'Wikislovník' => 'Wikislovníky',
1020                'Wikiverzita' => 'Wikiverzity',
1021            ],
1022            '5pl' => [
1023                'uživatel'    => 'uživatelé',
1024                'Wikibooks'   => 'Wikiknihy',
1025                'Wikifunctions' => 'Wikifunkce',
1026                'Wikinews'    => 'Wikizprávy',
1027                'Wikipedia'   => 'Wikipedie',
1028                'Wikiquote'   => 'Wikicitáty',
1029                'Wikisource'  => 'Wikizdroje',
1030                'Wikispecies' => 'Wikidruhy',
1031                'Wikiversity' => 'Wikiverzity',
1032                'Wikivoyage'  => 'Wikicesty',
1033                'Wiktionary'  => 'Wikislovníky',
1034                'Wikislovník' => 'Wikislovníky',
1035                'Wikiverzita' => 'Wikiverzity',
1036            ],
1037            '6pl' => [
1038                'uživatel'    => 'uživatelích',
1039                'Wikibooks'   => 'Wikiknihách',
1040                'Wikidata'    => 'Wikidatech',
1041                'Wikifunctions' => 'Wikifunkcích',
1042                'Wikinews'    => 'Wikizprávách',
1043                'Wikipedia'   => 'Wikipediích',
1044                'Wikiquote'   => 'Wikicitátech',
1045                'Wikisource'  => 'Wikizdrojích',
1046                'Wikispecies' => 'Wikidruzích',
1047                'Wikiversity' => 'Wikiverzitách',
1048                'Wikivoyage'  => 'Wikicestách',
1049                'Wiktionary'  => 'Wikislovnících',
1050                'Wikicesty'   => 'Wikicestách',
1051                'Wikicitáty'  => 'Wikicitátech',
1052                'Wikidruhy'   => 'Wikidruzích',
1053                'Wikifunkce'  => 'Wikifunkcích',
1054                'Wikiknihy'   => 'Wikiknihách',
1055                'Wikipedie'   => 'Wikipediích',
1056                'Wikislovník' => 'Wikislovnících',
1057                'Wikiverzita' => 'Wikiverzitách',
1058                'Wikizdroje'  => 'Wikizdrojích',
1059                'Wikizprávy'  => 'Wikizprávách',
1060            ],
1061            '7pl' => [
1062                'uživatel'    => 'uživateli',
1063                'Wikibooks'   => 'Wikiknihami',
1064                'Wikidata'    => 'Wikidaty',
1065                'Wikifunctions' => 'Wikifunkcemi',
1066                'Wikinews'    => 'Wikizprávami',
1067                'Wikipedia'   => 'Wikipediemi',
1068                'Wikiquote'   => 'Wikicitáty',
1069                'Wikisource'  => 'Wikizdroji',
1070                'Wikispecies' => 'Wikidruhy',
1071                'Wikiversity' => 'Wikiverzitami',
1072                'Wikivoyage'  => 'Wikicestami',
1073                'Wiktionary'  => 'Wikislovníky',
1074                'Wikicesty'   => 'Wikicestami',
1075                'Wikifunkce'  => 'Wikifunkcemi',
1076                'Wikiknihy'   => 'Wikiknihami',
1077                'Wikipedie'   => 'Wikipediemi',
1078                'Wikislovník' => 'Wikislovníky',
1079                'Wikiverzita' => 'Wikiverzitami',
1080                'Wikizdroje'  => 'Wikizdroji',
1081                'Wikizprávy'  => 'Wikizprávami',
1082            ],
1083        ];
1084
1085        $wgGrammarForms['dsb'] = [
1086            // genitive
1087            'genitiw' => [
1088                'Wikipedija'  => 'Wikipedije',
1089                'Wikiknihi'   => 'Wikiknih',
1090                'Wikinowiny'  => 'Wikinowin',
1091                'Wikižórło'   => 'Wikižórła',
1092                'Wikicitaty'  => 'Wikicitatow',
1093                'Wikisłownik' => 'Wikisłownika',
1094            ],
1095            // dative
1096            'datiw' => [
1097                'Wikipedija'  => 'Wikipediji',
1098                'Wikiknihi'   => 'Wikikniham',
1099                'Wikinowiny'  => 'Wikinowinam',
1100                'Wikižórło'   => 'Wikižórłu',
1101                'Wikicitaty'  => 'Wikicitatam',
1102                'Wikisłownik' => 'Wikisłownikej',
1103            ],
1104            // accusative
1105            'akuzativ' => [
1106                'Wikipedija'  => 'Wikipediju',
1107                'Wikiknihi'   => 'Wikiknknihi',
1108            ],
1109            // instrumental
1110            'instrumental' => [
1111                'Wikipedija'  => 'Wikipediju',
1112                'Wikiknihi'   => 'Wikiknihami',
1113                'Wikinowiny'  => 'Wikinowinami',
1114                'Wikižórło'   => 'Wikižórłom',
1115                'Wikicitaty'  => 'Wikicitatami',
1116                'Wikisłownik' => 'Wikisłownikom',
1117            ],
1118            // locative
1119            'lokatiw' => [
1120                'Wikipedija'  => 'Wikipediji',
1121                'Wikiknihi'   => 'Wikiknihach',
1122                'Wikinowiny'  => 'Wikinowinach',
1123                'Wikižórło'   => 'Wikižórłu',
1124                'Wikicitaty'  => 'Wikicitatach',
1125                'Wikisłownik' => 'Wikisłowniku',
1126            ],
1127        ];
1128
1129        $wgGrammarForms['fi'] = [
1130            'genitive' => [
1131                'Wikiuutiset' => 'Wikiuutisten',
1132                'Wikisitaatit' => 'Wikisitaattien',
1133                'Wikimedia Suomi' => 'Wikimedia Suomen',
1134                'Wikimatkat' => 'Wikimatkojen',
1135            ],
1136            'partitive' => [
1137                'Wikiuutiset' => 'Wikiuutisia',
1138                'Wikisitaatit' => 'Wikisitaatteja',
1139                'Wikimedia Suomi' => 'Wikimedia Suomea',
1140                'Wikimatkat' => 'Wikimatkoja',
1141            ],
1142            'elative' => [
1143                'Wikiuutiset' => 'Wikiuutisista',
1144                'Wikisitaatit' => 'Wikisitaateista',
1145                'Wikimedia Suomi' => 'Wikimedia Suomesta',
1146                'Wikimatkat' => 'Wikimatkoista',
1147            ],
1148            'inessive' => [
1149                'Wikiuutiset' => 'Wikiuutisissa',
1150                'Wikisitaatit' => 'Wikisitaateissa',
1151                'Wikimedia Suomi' => 'Wikimedia Suomessa',
1152                'Wikimatkat' => 'Wikimatkoissa',
1153            ],
1154            'illative' => [
1155                'Wikiuutiset' => 'Wikiuutisiin',
1156                'Wikisitaatit' => 'Wikisitaatteihin',
1157                'Wikimedia Suomi' => 'Wikimedia Suomeen',
1158                'Wikimatkat' => 'Wikimatkoihin',
1159            ],
1160        ];
1161
1162        $wgGrammarForms['ga'] = [
1163            'genitive' => [
1164                'Vicipéid'     => 'Vicipéide',
1165                'Vicífhoclóir' => 'Vicífhoclóra',
1166                'Vicíleabhair' => 'Vicíleabhar',
1167                'Vicíshliocht' => 'Vicíshleachta',
1168                'Vicífhoinse'  => 'Vicífhoinse',
1169                'Vicíghnéithe' => 'Vicíghnéithe',
1170                'Vicínuacht'   => 'Vicínuachta',
1171            ],
1172        ];
1173
1174        $wgGrammarForms['gsw'] = [
1175            // dative
1176            'dativ' => [
1177                'Wikipedia'       => 'vo de Wikipedia',
1178                'Wikinorchrichte' => 'vo de Wikinochrichte',
1179                'Wiktionaire'     => 'vom Wiktionaire',
1180                'Wikibuecher'     => 'vo de Wikibuecher',
1181                'Wikisprüch'      => 'vo de Wikisprüch',
1182                'Wikiquälle'      => 'vo de Wikiquälle',
1183            ],
1184            // accusative
1185            'akkusativ' => [
1186                'Wikipedia'       => 'd Wikipedia',
1187                'Wikinorchrichte' => 'd Wikinorchrichte',
1188                'Wiktionaire'     => 's Wiktionaire',
1189                'Wikibuecher'     => 'd Wikibuecher',
1190                'Wikisprüch'      => 'd Wikisprüch',
1191                'Wikiquälle'      => 'd Wikiquälle',
1192            ],
1193            // nominative
1194            'nominativ' => [
1195                'Wikipedia'       => 'd Wikipedia',
1196                'Wikinorchrichte' => 'd Wikinorchrichte',
1197                'Wiktionaire'     => 's Wiktionaire',
1198                'Wikibuecher'     => 'd Wikibuecher',
1199                'Wikisprüch'      => 'd Wikisprüch',
1200                'Wikiquälle'      => 'd Wikiquälle',
1201            ],
1202        ];
1203
1204        $wgGrammarForms['hsb'] = [
1205            // genitive
1206            'genitiw' => [
1207                'Wikipedija'  => 'Wikipedije',
1208                'Wikiknihi'   => 'Wikiknih',
1209                'Wikinowiny'  => 'Wikinowin',
1210                'Wikižórło'   => 'Wikižórła',
1211                'Wikicitaty'  => 'Wikicitatow',
1212                'Wikisłownik' => 'Wikisłownika',
1213            ],
1214            // dative
1215            'datiw' => [
1216                'Wikipedija'  => 'Wikipediji',
1217                'Wikiknihi'   => 'Wikikniham',
1218                'Wikinowiny'  => 'Wikinowinam',
1219                'Wikižórło'   => 'Wikižórłu',
1220                'Wikicitaty'  => 'Wikicitatam',
1221                'Wikisłownik' => 'Wikisłownikej',
1222            ],
1223            // accusative
1224            'akuzativ' => [
1225                'Wikipedija'  => 'Wikipediju',
1226                'Wikiknihi'   => 'Wikiknknihi',
1227            ],
1228            // instrumental
1229            'instrumental' => [
1230                'Wikipedija'  => 'Wikipediju',
1231                'Wikiknihi'   => 'Wikiknihami',
1232                'Wikinowiny'  => 'Wikinowinami',
1233                'Wikižórło'   => 'Wikižórłom',
1234                'Wikicitaty'  => 'Wikicitatami',
1235                'Wikisłownik' => 'Wikisłownikom',
1236            ],
1237            // locative
1238            'lokatiw' => [
1239                'Wikipedija'  => 'Wikipediji',
1240                'Wikiknihi'   => 'Wikiknihach',
1241                'Wikinowiny'  => 'Wikinowinach',
1242                'Wikižórło'   => 'Wikižórłu',
1243                'Wikicitaty'  => 'Wikicitatach',
1244                'Wikisłownik' => 'Wikisłowniku',
1245            ],
1246        ];
1247
1248        $wgGrammarForms['hu'] = [
1249            'rol' => [
1250                'Wikipédia'   => 'Wikipédiáról',
1251                'Wikidézet'   => 'Wikidézetről',
1252                'Wikiszótár'  => 'Wikiszótárról',
1253                'Wikikönyvek' => 'Wikikönyvekről',
1254            ],
1255            'ba' => [
1256                'Wikipédia'   => 'Wikipédiába',
1257                'Wikidézet'   => 'Wikidézetbe',
1258                'Wikiszótár'  => 'Wikiszótárba',
1259                'Wikikönyvek' => 'Wikikönyvekbe',
1260            ],
1261            'k' => [
1262                'Wikipédia'   => 'Wikipédiák',
1263                'Wikidézet'   => 'Wikidézetek',
1264                'Wikiszótár'  => 'Wikiszótárak',
1265            ],
1266        ];
1267        // T289767
1268        $wgGrammarForms['ks'] = [
1269            // ergative
1270            'کرٛاوَل' => [
1271                'وِکیٖلۄغَتھ' => 'وِکیٖلۄغتَن',
1272            ],
1273            // dative
1274            'دُکرٛٲوؠ' => [
1275                'وِکیٖلۄغَتھ' => 'وِکیٖلۄغتَس',
1276            ],
1277            // ablative
1278            'آیِتؠ' => [
1279                'وِکیٖلۄغَتھ' => 'وِکیٖلۄغتہٕ',
1280            ],
1281        ];
1282        $wgGrammarForms['la'] = [
1283            'genitive' => [
1284                'Vicimedia Communia' => 'Vicimediorum Communium',
1285            ],
1286            'ablative' => [
1287                'Vicimedia Communia' => 'Vicimediis Communibus',
1288            ],
1289        ];
1290
1291        $wgGrammarForms['lv'] = [
1292            'ģenitīvs' => [
1293                'Vikipēdija'   => 'Vikipēdijas',
1294                'Vikivārdnīca' => 'Vikivārdnīcas',
1295            ],
1296            'datīvs' => [
1297                'Vikipēdija'   => 'Vikipēdijai',
1298                'Vikivārdnīca' => 'Vikivārdnīcai',
1299            ],
1300            'akuzatīvs' => [
1301                'Vikipēdija'   => 'Vikipēdiju',
1302                'Vikivārdnīca' => 'Vikivārdnīcu',
1303            ],
1304            'lokatīvs' => [
1305                'Vikipēdija'   => 'Vikipēdijā',
1306                'Vikivārdnīca' => 'Vikivārdnīcā',
1307            ],
1308        ];
1309
1310        $wgGrammarForms['pl'] = [
1311            'D.lp' => [
1312                'Wikicytaty'   => 'Wikicytatów',
1313                'Wikipedia'    => 'Wikipedii',
1314                'Wikipodróże'  => 'Wikipodróży',
1315                'Wikisłownik'  => 'Wikisłownika',
1316                'Wikiźródła'   => 'Wikiźródeł',
1317                'Wikidane'     => 'Wikidanych',
1318                'Wikimania'    => 'Wikimanii',
1319                'Wikifunkcje'  => 'Wikifunkcji',
1320            ],
1321            'C.lp' => [
1322                'Wikicytaty'   => 'Wikicytatom',
1323                'Wikipedia'    => 'Wikipedii',
1324                'Wikipodróże'  => 'Wikipodróżom',
1325                'Wikisłownik'  => 'Wikisłownikowi',
1326                'Wikiźródła'   => 'Wikiźródłom',
1327                'Wikidane'     => 'Wikidanym',
1328                'Wikimania'    => 'Wikimanii',
1329                'Wikifunkcje'  => 'Wikifunkcjom',
1330            ],
1331            'B.lp' => [
1332                'Wikipedia'    => 'Wikipedię',
1333                'Wikimania'    => 'Wikimanię',
1334            ],
1335            'N.lp' => [
1336                'Wikicytaty'   => 'Wikicytatami',
1337                'Wikipedia'    => 'Wikipedią',
1338                'Wikipodróże'  => 'Wikipodróżami',
1339                'Wikisłownik'  => 'Wikisłownikiem',
1340                'Wikiźródła'   => 'Wikiźródłami',
1341                'Wikidane'     => 'Wikidanymi',
1342                'Wikimania'    => 'Wikimanią',
1343                'Wikifunkcje'  => 'Wikifunkcjami',
1344            ],
1345            'MS.lp' => [
1346                'Wikicytaty'   => 'Wikicytatach',
1347                'Wikipedia'    => 'Wikipedii',
1348                'Wikipodróże'  => 'Wikipodróżach',
1349                'Wikisłownik'  => 'Wikisłowniku',
1350                'Wikiźródła'   => 'Wikiźródłach',
1351                'Wikidane'     => 'Wikidanych',
1352                'Wikimania'    => 'Wikimanii',
1353                'Wikifunkcje'  => 'Wikifunkcjach',
1354            ],
1355            'W.lp' => [
1356                'Wikipedia'    => 'Wikipedio',
1357                'Wikisłownik'  => 'Wikisłowniku',
1358                'Wikimania'    => 'Wikimanio',
1359            ],
1360        ];
1361
1362        $wgGrammarForms['rmy'] = [
1363            // genitive (m.sg.)
1364            'genitive-m-sg' => [
1365                'Vikipidiya' => 'Vikipidiyako',
1366                'Vikcyonaro' => 'Vikcyonaresko',
1367            ],
1368            // genitive (f.sg.)
1369            'genitive-f-sg' => [
1370                'Vikipidiya' => 'Vikipidiyaki',
1371                'Vikcyonaro' => 'Vikcyonareski',
1372            ],
1373            // genitive (pl.)
1374            'genitive-pl' => [
1375                'Vikipidiya' => 'Vikipidiyake',
1376                'Vikcyonaro' => 'Vikcyonareske',
1377            ],
1378            // dative
1379            'dativ' => [
1380                'Vikipidiya' => 'Wikipediji',
1381                'Vikcyonaro' => 'Vikcyonareske',
1382            ],
1383            // locative
1384            'locative' => [
1385                'Vikipidiya' => 'Wikipedijo',
1386                'Vikcyonaro' => 'Vikcyonareste',
1387            ],
1388            // ablative
1389            'ablative' => [
1390                'Vikipidiya' => 'o Wikipediji',
1391                'Vikcyonaro' => 'Vikcyonarestar',
1392            ],
1393            // instrumental
1394            'instrumental' => [
1395                'Vikipidiya' => 'z Wikipedijo',
1396                'Vikcyonaro' => 'Vikcyonaresa',
1397            ],
1398        ];
1399
1400        $wgGrammarForms['sh'] = [
1401            'genitiv' => [
1402                'Wikiknjige'          => 'Wikiknjiga',
1403                'Wikipodaci'          => 'Wikipodataka',
1404                'Wikifunkcije'        => 'Wikifunkcija',
1405                'Wikimedijina ostava' => 'Wikimedijine ostave',
1406                'Wikipedija'          => 'Wikipedije',
1407                'Wikicitat'           => 'Wikicitata',
1408                'Wikiteka'            => 'Wikiteke',
1409                'Wikivrste'           => 'Wikivrsta',
1410                'Wikiverzitet'        => 'Wikiverziteta',
1411                'Wikivodič'           => 'Wikivodiča',
1412                'Wikirječnik'         => 'Wikirječnika',
1413                'projekt'             => 'projekta',
1414            ],
1415            'dativ' => [
1416                'Wikiknjige'          => 'Wikiknjigama',
1417                'Wikipodaci'          => 'Wikipodacima',
1418                'Wikifunkcije'        => 'Wikifunkcijama',
1419                'Wikimedijina ostava' => 'Wikimedijinoj ostavi',
1420                'Wikinovosti'         => 'Wikinovostima',
1421                'Wikipedija'          => 'Wikipediji',
1422                'Wikicitat'           => 'Wikicitatu',
1423                'Wikiteka'            => 'Wikiteci',
1424                'Wikivrste'           => 'Wikivrstama',
1425                'Wikiverzitet'        => 'Wikiverzitetu',
1426                'Wikivodič'           => 'Wikivodiču',
1427                'Wikirječnik'         => 'Wikirječniku',
1428                'projekt'             => 'projektu',
1429            ],
1430            'akuzativ' => [
1431                'Wikipodaci'          => 'Wikipodatke',
1432                'Wikimedijina ostava' => 'Wikimedijinu ostavu',
1433                'Wikipedija'          => 'Wikipediju',
1434                'Wikiteka'            => 'Wikiteku',
1435                // To support the descriptive declension
1436                'projekt'             => 'projekt',
1437            ],
1438            'vokativ' => [
1439                'Wikimedijina ostava' => 'Wikimedijina ostavo',
1440                'Wikipedija'          => 'Wikipedijo',
1441                'Wikicitat'           => 'Wikicitate',
1442                'Wikiteka'            => 'Wikiteko',
1443                'Wikiverzitet'        => 'Wikiverzitete',
1444                'Wikivodič'           => 'Wikivodiču',
1445                'Wikirječnik'         => 'Wikirječniče',
1446                'projekt'             => 'projekte',
1447            ],
1448            'instrumental' => [
1449                'Wikiknjige'          => 'Wikiknjigama',
1450                'Wikipodaci'          => 'Wikipodacima',
1451                'Wikifunkcije'        => 'Wikifunkcijama',
1452                'Wikimedijina ostava' => 'Wikimedijinom ostavom',
1453                'Wikinovosti'         => 'Wikinovostima',
1454                'Wikipedija'          => 'Wikipedijom',
1455                'Wikicitat'           => 'Wikicitatom',
1456                'Wikiteka'            => 'Wikitekom',
1457                'Wikivrste'           => 'Wikivrstama',
1458                'Wikiverzitet'        => 'Wikiverzitetom',
1459                'Wikivodič'           => 'Wikivodičem',
1460                'Wikirječnik'         => 'Wikirječnikom',
1461                'projekt'             => 'projektom',
1462            ],
1463            'lokativ' => [
1464                'Wikiknjige'          => 'Wikiknjigama',
1465                'Wikipodaci'          => 'Wikipodacima',
1466                'Wikifunkcije'        => 'Wikifunkcijama',
1467                'Wikimedijina ostava' => 'Wikimedijinoj ostavi',
1468                'Wikinovosti'         => 'Wikinovostima',
1469                'Wikipedija'          => 'Wikipediji',
1470                'Wikicitat'           => 'Wikicitatu',
1471                'Wikiteka'            => 'Wikiteci',
1472                'Wikivrste'           => 'Wikivrstama',
1473                'Wikiverzitet'        => 'Wikiverzitetu',
1474                'Wikivodič'           => 'Wikivodiču',
1475                'Wikirječnik'         => 'Wikirječniku',
1476                'projekt'             => 'projektu',
1477            ],
1478        ];
1479
1480        $wgGrammarForms['sk'] = [
1481            'genitív' => [
1482                'Wikipédia'   => 'Wikipédie',
1483                'Wikislovník' => 'Wikislovníku',
1484                'Wikicitáty'  => 'Wikicitátov',
1485                'Wikiknihy'   => 'Wikikníh',
1486            ],
1487            'datív' => [
1488                'Wikipédia'   => 'Wikipédii',
1489                'Wikislovník' => 'Wikislovníku',
1490                'Wikicitáty'  => 'Wikicitátom',
1491                'Wikiknihy'   => 'Wikiknihám',
1492            ],
1493            'akuzatív' => [
1494                'Wikipédia'   => 'Wikipédiu',
1495                'Wikislovník' => 'Wikislovník',
1496                'Wikicitáty'  => 'Wikicitáty',
1497                'Wikiknihy'   => 'Wikiknihy',
1498            ],
1499            'lokál' => [
1500                'Wikipédia'   => 'Wikipédii',
1501                'Wikislovník' => 'Wikislovníku',
1502                'Wikicitáty'  => 'Wikicitátoch',
1503                'Wikiknihy'   => 'Wikiknihách',
1504            ],
1505            'inštrumentál' => [
1506                'Wikipédia'   => 'Wikipédiou',
1507                'Wikislovník' => 'Wikislovníkom',
1508                'Wikicitáty'  => 'Wikicitátmi',
1509                'Wikiknihy'   => 'Wikiknihami',
1510            ],
1511        ];
1512
1513        $wgGrammarForms['sl'] = [
1514            // genitive
1515            'rodilnik' => [
1516                'Wikipedija'  => 'Wikipedije',
1517                'Wikiknjige'  => 'Wikiknjig',
1518                'Wikinovice'  => 'Wikinovic',
1519                'Wikinavedek' => 'Wikinavedka',
1520                'Wikivir'     => 'Wikivira',
1521                'Wikislovar'  => 'Wikislovarja',
1522            ],
1523            // dative
1524            'dajalnik' => [
1525                'Wikipedija'  => 'Wikipediji',
1526                'Wikiknjige'  => 'Wikiknjigam',
1527                'Wikinovice'  => 'Wikinovicam',
1528                'Wikinavedek' => 'Wikinavedku',
1529                'Wikivir'     => 'Wikiviru',
1530                'Wikislovar'  => 'Wikislovarju',
1531            ],
1532            // accusative
1533            'tožilnik' => [
1534                'Wikipedija'  => 'Wikipedijo',
1535                // no need to transform the others
1536            ],
1537            // locative
1538            'mestnik' => [
1539                'Wikipedija'  => 'o Wikipediji',
1540                'Wikiknjige'  => 'o Wikiknjigah',
1541                'Wikinovice'  => 'o Wikinovicah',
1542                'Wikinavedek' => 'o Wikinavedku',
1543                'Wikivir'     => 'o Wikiviru',
1544                'Wikislovar'  => 'o Wikislovarju',
1545            ],
1546            // instrumental
1547            'orodnik' => [
1548                'Wikipedija'  => 'z Wikipedijo',
1549                'Wikiknjige'  => 'z Wikiknjigami',
1550                'Wikinovice'  => 'z Wikinovicami',
1551                'Wikinavedek' => 'z Wikinavedkom',
1552                'Wikivir'     => 'z Wikivirom',
1553                'Wikislovar'  => 'z Wikislovarjem',
1554            ],
1555        ];
1556
1557        $wgGrammarForms['sr-ec'] =
1558        $wgGrammarForms['sr-cyrl'] = [
1559            // genitive
1560            'генитив' => [
1561                'Викиречник'  => 'Викиречника',
1562                'Викицитат'   => 'Викицитата',
1563                'Викизворник' => 'Викизворника',
1564                'Викикњиге'   => 'Викикњига',
1565                'Википедија'  => 'Википедије',
1566                'Википодаци'  => 'Википодатака',
1567                'Викимедијина остава' => 'Викимедијине оставе',
1568                'Викиверзитет' => 'Викиверзитета',
1569            ],
1570            // dative
1571            'датив' => [
1572                'Викиречник'  => 'Викиречнику',
1573                'Викицитат'   => 'Викицитату',
1574                'Викизворник' => 'Викизворнику',
1575                'Викикњиге'   => 'Викикњигама',
1576                'Википедија'  => 'Википедији',
1577                'Википодаци'  => 'Википодацима',
1578                'Викиновости'   => 'Викиновистима',
1579                'Викимедијина остава' => 'Викимедијиној остави',
1580                'Викиверзитет' => 'Викиверзитету',
1581            ],
1582            // accusative
1583            'акузатив' => [
1584                'Викиречник'  => 'Викиречник',
1585                'Викицитат'   => 'Викицитат',
1586                'Викизворник' => 'Викизворник',
1587                'Википедија'  => 'Википедију',
1588                'Википодаци'  => 'Википодатке',
1589            ],
1590            // vocative
1591            'вокатив' => [
1592                'Викиречник'  => 'Викиречниче',
1593                'Викизворник' => 'Викизворниче',
1594                'Википедија'  => 'Википедијо',
1595                'Викимедијина остава' => 'Викимедијина оставо',
1596                'Викиверзитет' => 'Викиверзитету',
1597            ],
1598            // instrumental
1599            'инструментал' => [
1600                'Викиречник'  => 'Викиречником',
1601                'Викицитат'   => 'Викицитатом',
1602                'Викизворник' => 'Викизворником',
1603                'Викикњиге'   => 'Викикњигама',
1604                'Википедија'  => 'Википедијом',
1605                'Википодаци'  => 'Википодацима',
1606                'Викиновости'   => 'Викиновостима',
1607                'Викимедијина остава' => 'Викимедијином оставом',
1608                'Викиверзитет' => 'Викиверзитетом',
1609            ],
1610            // locative
1611            'локатив' => [
1612                'Викиречник'  => 'Викиречнику',
1613                'Викицитат'   => 'Викицитату',
1614                'Викизворник' => 'Викизворнику',
1615                'Викикњиге'   => 'Викикњигама',
1616                'Википедија'  => 'Википедији',
1617                'Википодаци'  => 'Википодацима',
1618                'Викиновости'   => 'Викиновостима',
1619                'Викимедијина остава' => 'Викимедијиној остави',
1620                'Викиверзитет' => 'Викиверзитету',
1621            ],
1622        ];
1623
1624        $wgGrammarForms['sr-el'] =
1625        $wgGrammarForms['sr-latn'] = [
1626            // genitive
1627            'genitiv' => [
1628                'Vikirečnik'  => 'Vikirečnika',
1629                'Vikicitat'   => 'Vikicitata',
1630                'Vikizvornik' => 'Vikizvornika',
1631                'Vikiknjige'  => 'Vikiknjiga',
1632                'Vikipedija'  => 'Vikipedije',
1633                'Vikipodaci'  => 'Vikipodataka',
1634                'Vikimedijina ostava' => 'Vikimedijine ostave',
1635                'Vikiverzitet' => 'Vikiverziteta',
1636            ],
1637            // dative
1638            'dativ' => [
1639                'Vikirečnik'  => 'Vikirečniku',
1640                'Vikicitat'   => 'Vikicitatu',
1641                'Vikizvornik' => 'Vikizvorniku',
1642                'Vikiknjige'  => 'Vikiknjigama',
1643                'Vikipedija'  => 'Vikipediji',
1644                'Vikipodaci'  => 'Vikipodacima',
1645                'Vikinovosti'   => 'Vikinovostima',
1646                'Vikimedijina ostava' => 'Vikimedijinoj ostavi',
1647                'Vikiverzitet' => 'Vikiverzitetu',
1648            ],
1649            // accusative
1650            'akuzativ' => [
1651                'Vikirečnik'  => 'Vikirečnik',
1652                'Vikicitat'   => 'Vikicitat',
1653                'Vikizvornik' => 'Vikizvornik',
1654                'Vikipedija'  => 'Vikipediju',
1655                'Vikipodaci'  => 'Vikipodatke',
1656            ],
1657            // vocative
1658            'vokativ' => [
1659                'Vikirečnik'  => 'Vikirečniče',
1660                'Vikizvornik' => 'Vikizvorniče',
1661                'Vikipedija'  => 'Vikipedijo',
1662                'Vikimedijina ostava' => 'Vikimedijina ostavo',
1663                'Vikiverzitet' => 'Vikiverzitetu',
1664            ],
1665            // instrumental
1666            'instrumental' => [
1667                'Vikirečnik'  => 'Vikirečnikom',
1668                'Vikicitat'   => 'Vikicitatom',
1669                'Vikizvornik' => 'Vikizvornikom',
1670                'Vikiknjige'  => 'Vikiknjigama',
1671                'Vikipedija'  => 'Vikipedijom',
1672                'Vikipodaci'  => 'Vikipodacima',
1673                'Vikinovosti'   => 'Vikinovostima',
1674                'Vikimedijina ostava' => 'Vikimedijinom ostavom',
1675                'Vikiverzitet' => 'Vikiverzitetom',
1676            ],
1677            // locative
1678            'lokativ' => [
1679                'Vikirečnik'  => 'Vikirečniku',
1680                'Vikicitat'   => 'Vikicitatu',
1681                'Vikizvornik' => 'Vikizvorniku',
1682                'Vikiknjige'  => 'Vikiknjigama',
1683                'Vikipedija'  => 'Vikipediji',
1684                'Vikipodaci'  => 'Vikipodacima',
1685                'Vikinovosti'   => 'Vikinovostima',
1686                'Vikimedijina ostava' => 'Vikimedijinoj ostavi',
1687                'Vikiverzitet' => 'Vikiverzitetu',
1688            ],
1689        ];
1690
1691        $wgGrammarForms['uk'] = [
1692            // genitive
1693            'genitive' => [
1694                'Вікіпедія' => 'Вікіпедії',
1695                'Вікісловник' => 'Вікісловника',
1696                'Вікісховище' => 'Вікісховища',
1697                'Вікіпідручник' => 'Вікіпідручника',
1698                'Вікіцитати' => 'Вікіцитат',
1699                'Вікіджерела' => 'Вікіджерел',
1700                'Вікіновини' => 'Вікіновин',
1701                'Вікідані' => 'Вікіданих',
1702                'Вікімандри' => 'Вікімандрів',
1703            ],
1704            // dative
1705            'dative' => [
1706                'Вікіпедія' => 'Вікіпедії',
1707                'Вікісловник' => 'Вікісловнику',
1708                'Вікісховище' => 'Вікісховищу',
1709                'Вікіпідручник' => 'Вікіпідручнику',
1710                'Вікіцитати' => 'Вікіцитатам',
1711                'Вікіджерела' => 'Вікіджерелам',
1712                'Вікіновини' => 'Вікіновинам',
1713                'Вікідані' => 'Вікіданим',
1714                'Вікімандри' => 'Вікімандрам',
1715            ],
1716            // accusative
1717            'accusative' => [
1718                'Вікіпедія' => 'Вікіпедію',
1719                'Вікісловник' => 'Вікісловник',
1720                'Вікісховище' => 'Вікісховище',
1721                'Вікіпідручник' => 'Вікіпідручник',
1722                'Вікіцитати' => 'Вікіцитати',
1723                'Вікіджерела' => 'Вікіджерела',
1724                'Вікіновини' => 'Вікіновини',
1725                'Вікідані' => 'Вікідані',
1726                'Вікімандри' => 'Вікімандри',
1727            ],
1728            // instrumental
1729            'instrumental' => [
1730                'Вікіпедія' => 'Вікіпедією',
1731                'Вікісловник' => 'Вікісловником',
1732                'Вікісховище' => 'Вікісховищем',
1733                'Вікіпідручник' => 'Вікіпідручником',
1734                'Вікіцитати' => 'Вікіцитатами',
1735                'Вікіджерела' => 'Вікіджерелами',
1736                'Вікіновини' => 'Вікіновинами',
1737                'Вікідані' => 'Вікіданими',
1738                'Вікімандри' => 'Вікімандрами',
1739            ],
1740            // locative
1741            'locative' => [
1742                'Вікіпедія' => 'у Вікіпедії',
1743                'Вікісловник' => 'у Вікісловнику',
1744                'Вікісховище' => 'у Вікісховищі',
1745                'Вікіпідручник' => 'у Вікіпідручнику',
1746                'Вікіцитати' => 'у Вікіцитатах',
1747                'Вікіджерела' => 'у Вікіджерелах',
1748                'Вікіновини' => 'у Вікіновинах',
1749                'Вікідані' => 'у Вікіданих',
1750                'Вікімандри' => 'у Вікімандрах',
1751            ],
1752            // vocative
1753            'vocative' => [
1754                'Вікіпедія' => 'Вікіпедіє',
1755                'Вікісловник' => 'Вікісловнику',
1756                'Вікісховище' => 'Вікісховище',
1757                'Вікіпідручник' => 'Вікіпідручнику',
1758                'Вікіцитати' => 'Вікіцитати',
1759                'Вікіджерела' => 'Вікіджерела',
1760                'Вікіновини' => 'Вікіновини',
1761                'Вікідані' => 'Вікідані',
1762                'Вікімандри' => 'Вікімандри',
1763            ],
1764        ];
1765
1766        // Avoid weirdness if both extensions are loaded at the same time.
1767        if ( !ExtensionRegistry::getInstance()->isLoaded( 'UserMerge' ) ) {
1768            global $wgLogTypes, $wgLogNames, $wgLogHeaders, $wgLogActionsHandlers, $wgActionFilteredLogs;
1769
1770            $wgLogTypes[] = 'usermerge';
1771            $wgLogNames['usermerge'] = 'wikimedia-usermerge-logpage';
1772            $wgLogHeaders['usermerge'] = 'wikimedia-usermerge-logpagetext';
1773
1774            $wgLogActionsHandlers['usermerge/*'] = WMUserMergeLogFormatter::class;
1775            $wgActionFilteredLogs['usermerge'] = [
1776                'mergeuser'  => [ 'mergeuser' ],
1777                'deleteuser' => [ 'deleteuser' ],
1778            ];
1779        }
1780    }
1781
1782    /**
1783     * Called every time wikitext is added to the OutputPage, after it is parsed but before it is added.
1784     *
1785     * @param OutputPage $out The Output page object
1786     * @param string &$text Text that will be displayed, in HTML
1787     */
1788    public function onOutputPageBeforeHTML( $out, &$text ): void {
1789        $skins = $out->getConfig()->get( 'WikimediaStylesSkins' );
1790
1791        if ( in_array( $out->getSkin()->getSkinName(), $skins ) ) {
1792            $out->addModuleStyles( [ 'ext.wikimediamessages.styles' ] );
1793        }
1794    }
1795
1796    /**
1797     * @see https://www.mediawiki.org/wiki/Manual:Hooks/ResourceLoaderRegisterModules
1798     *
1799     * @param ResourceLoader $resourceLoader
1800     */
1801    public function onResourceLoaderRegisterModules( ResourceLoader $resourceLoader ): void {
1802        if ( $this->extensionRegistry->isLoaded( 'IPInfo' ) ) {
1803            $resourceLoader->register( 'ext.wikimediaMessages.ipInfo.hooks', [
1804                'localBasePath' => dirname( __DIR__ ) . '/modules/ext.wikimediaMessages.ipInfo.hooks',
1805                'remoteExtPath' => 'WikimediaMessages/modules/ext.wikimediaMessages.ipInfo.hooks',
1806                'scripts' => 'infobox.js',
1807                'styles' => 'infobox.less',
1808                'messages' => [
1809                    'ipinfo-global-contributions-url-label',
1810                    'ipinfo-global-contributions-url',
1811                    'ipinfo-xtools-url-label',
1812                    'ipinfo-xtools-url',
1813                ],
1814                'dependencies' => [
1815                    'ext.ipInfo',
1816                ],
1817            ] );
1818        }
1819    }
1820
1821    /**
1822     * Handle SpecialPageBeforeExecute hook
1823     *
1824     * @param SpecialPage $special
1825     * @param string|null $subPage
1826     */
1827    public function onSpecialPageBeforeExecute( $special, $subPage ) {
1828        $this->addIPInfoLinks( $special, $subPage );
1829    }
1830
1831    /**
1832     * @param SpecialPage $special
1833     * @param string|null $subPage
1834     */
1835    private function addIPInfoLinks( $special, $subPage ): void {
1836        if (
1837            $special->getName() !== 'Contributions' &&
1838            $special->getName() !== 'DeletedContributions'
1839        ) {
1840            return;
1841        }
1842
1843        // Return if target is not an IP address
1844        if ( $subPage === null || !IPUtils::isValid( $subPage ) ) {
1845            return;
1846        }
1847
1848        $accessingUser = $special->getUser();
1849        $isBetaFeaturesLoaded = $this->extensionRegistry->isLoaded( 'BetaFeatures' );
1850
1851        // Check the same permissions and preferences as
1852        // MediaWiki\IPInfo\HookHandler\InfoboxHandler
1853        if (
1854            !$this->permissionManager->userHasRight( $accessingUser, 'ipinfo' ) ||
1855            ( $isBetaFeaturesLoaded &&
1856                !$this->userOptionsLookup->getOption( $accessingUser, 'ipinfo-beta-feature-enable' ) )
1857        ) {
1858            return;
1859        }
1860
1861        $special->getOutput()->addModules( 'ext.wikimediaMessages.ipInfo.hooks' );
1862    }
1863
1864    /**
1865     * Whether or not the donate link should be moved from the sidebar to the user menu
1866     *
1867     * @param Skin $skin
1868     * @return bool
1869     */
1870    public function shouldMoveDonateLink( $skin ): bool {
1871        $config = $skin->getConfig();
1872        $user = $skin->getUser();
1873
1874        if (
1875            $skin->getSkinName() === 'vector-2022' &&
1876            $config->get( 'WikimediaMessagesAnonDonateLink' ) &&
1877            $user->isAnon()
1878        ) {
1879            return true;
1880        }
1881        return false;
1882    }
1883
1884    /**
1885     * Add a donate link to the user links menu for anonymous users on vector '22, if feature flag is turned on
1886     *
1887     * @param SkinTemplate $skin
1888     * @param array &$links
1889     */
1890    public function onSkinTemplateNavigation__Universal( $skin, &$links ): void {
1891        $context = $skin->getContext();
1892
1893        if ( $this->shouldMoveDonateLink( $skin ) ) {
1894            $sitesupport = [ 'sitesupport' => [
1895                'text' => $context->msg( 'sitesupport' )->text(),
1896                'href' => $context->msg( 'sitesupport-url' )->text(),
1897                'title' => $context->msg( 'tooltip-n-sitesupport' )->text(),
1898            ] ];
1899            // Ensure donate link goes before other links
1900            if ( array_key_exists( 'user-menu', $links ) ) {
1901                $links['user-menu'] = $sitesupport + $links['user-menu'];
1902            }
1903        }
1904    }
1905
1906    /**
1907     * Remove the donate link for anonymous users on vector '22, if the feature flag is turned on
1908     *
1909     * @param Skin $skin
1910     * @param array &$sidebar
1911     */
1912    public function onSidebarBeforeOutput( $skin, &$sidebar ): void {
1913        // we want to be sure we're only removing this link if it's going to appear elsewhere
1914        if ( $this->shouldMoveDonateLink( $skin ) ) {
1915            // the donate link is not guaranteed to be in a particular section, so we must traverse them all
1916            foreach ( $sidebar as $section => $links ) {
1917                // every other array length is bounded by practicality, but skip looping over language for peformance
1918                if ( $section === 'LANGUAGES' ) {
1919                    continue;
1920                }
1921
1922                foreach ( $links as $index => $link ) {
1923                    if ( isset( $link['id'] ) && $link['id'] === 'n-sitesupport' ) {
1924                        unset( $sidebar[$section][$index] );
1925                    }
1926                }
1927            }
1928        }
1929    }
1930}