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