jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/366469 )

Change subject: Rebased on top of the current GlobalUserPage codebase with 
s/GlobalUserPage/SharedHelpPage(s)/g
......................................................................


Rebased on top of the current GlobalUserPage codebase with 
s/GlobalUserPage/SharedHelpPage(s)/g

Now proper stylesheets are loaded if a page is using the <gallery> tag,
such as on [[s:Help:Reporting a problem]].

Change-Id: I4f964f3b684d9d8c5812458017f05b941f80e3af
---
A LocalSharedHelpPageCacheUpdateJob.php
A SharedHelpPage.body.php
A SharedHelpPageCacheInvalidator.php
A SharedHelpPageLocalJobSubmitJob.php
A SharedHelpPagePage.php
D SharedHelpPages.body.php
M SharedHelpPages.hooks.php
M extension.json
M i18n/ast.json
M i18n/bn.json
M i18n/de.json
M i18n/en.json
M i18n/fi.json
M i18n/fr.json
M i18n/gl.json
M i18n/hsb.json
M i18n/ie.json
M i18n/it.json
M i18n/ja.json
M i18n/ko.json
M i18n/lb.json
M i18n/mk.json
M i18n/nl.json
M i18n/pt-br.json
M i18n/qqq.json
M i18n/ru.json
M i18n/uk.json
M i18n/zh-hans.json
28 files changed, 814 insertions(+), 430 deletions(-)

Approvals:
  Jack Phoenix: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/LocalSharedHelpPageCacheUpdateJob.php 
b/LocalSharedHelpPageCacheUpdateJob.php
new file mode 100644
index 0000000..c33ace9
--- /dev/null
+++ b/LocalSharedHelpPageCacheUpdateJob.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * A job that runs on local wikis to purge Squid and possibly
+ * queue local HTMLCacheUpdate jobs
+ */
+class LocalSharedHelpPageCacheUpdateJob extends Job {
+       /**
+        * @param Title $title
+        * @param array $params Should have 'pagename' and 'touch' keys
+        */
+       public function __construct( Title $title, array $params ) {
+               parent::__construct( 'LocalSharedHelpPageCacheUpdateJob', 
$title, $params );
+       }
+
+       public function run() {
+               $title = Title::makeTitleSafe( NS_HELP, 
$this->params['pagename'] );
+               // We want to purge the cache of the accompanying page so the 
tabs change colors
+               $other = $title->getOtherPage();
+
+               $title->purgeSquid();
+               $other->purgeSquid();
+               HTMLFileCache::clearFileCache( $title );
+               HTMLFileCache::clearFileCache( $other );
+               if ( $this->params['touch'] ) {
+                       $title->touchLinks();
+               }
+       }
+}
diff --git a/SharedHelpPage.body.php b/SharedHelpPage.body.php
new file mode 100644
index 0000000..a065d38
--- /dev/null
+++ b/SharedHelpPage.body.php
@@ -0,0 +1,346 @@
+<?php
+
+class SharedHelpPage extends Article {
+
+       /**
+        * Cache version of action=parse
+        * output
+        */
+       const PARSED_CACHE_VERSION = 2;
+
+       /**
+        * @var Config
+        */
+       private $config;
+
+       /**
+        * @var BagOStuff
+        */
+       private $cache;
+
+       /**
+        * @var MapCacheLRU
+        */
+       private static $displayCache;
+
+       /**
+        * @var MapCacheLRU
+        */
+       private static $touchedCache;
+
+       public function __construct( Title $title, Config $config ) {
+               global $wgMemc;
+               $this->config = $config;
+               $this->cache = $wgMemc;
+               parent::__construct( $title );
+       }
+
+       public function showMissingArticle() {
+               $title = $this->getTitle();
+
+               if ( !self::shouldDisplaySharedPage( $title ) ) {
+                       parent::showMissingArticle();
+                       return;
+               }
+
+               $out = $this->getContext()->getOutput();
+               $parsedOutput = $this->getRemoteParsedText( 
self::getCentralTouched( $title ) );
+
+               // If the help page is empty or the API request failed, show 
the normal
+               // missing article page
+               if ( !$parsedOutput || !trim( $parsedOutput['text'] ) ) {
+                       parent::showMissingArticle();
+                       return;
+               }
+
+               $out->addHTML( $parsedOutput['text'] );
+               $out->addModuleStyles( 'ext.SharedHelpPages' );
+
+               // Load ParserOutput modules...
+               $this->loadModules( $out, $parsedOutput );
+       }
+
+       /**
+        * Attempts to load modules through the
+        * ParserOutput on the local wiki, if
+        * they exist.
+        *
+        * @param OutputPage $out
+        * @param array $parsedOutput
+        */
+       private function loadModules( OutputPage $out, array $parsedOutput ) {
+               $rl = $out->getResourceLoader();
+               $map = [
+                       'modules' => 'addModules',
+                       'modulestyles' => 'addModuleStyles',
+                       'modulescripts' => 'addModuleScripts',
+               ];
+               foreach ( $map as $type => $func ) {
+                       foreach ( $parsedOutput[$type] as $module ) {
+                               if ( $rl->isModuleRegistered( $module ) ) {
+                                       $out->$func( $module );
+                               }
+                       }
+               }
+
+               $out->addJsConfigVars( $parsedOutput['jsconfigvars'] );
+       }
+
+       /**
+        * Given a Title, assuming it doesn't exist, should
+        * we display a shared help page on it
+        *
+        * @param Title $title
+        * @return bool
+        */
+       public static function shouldDisplaySharedPage( Title $title ) {
+               global $wgSharedHelpPagesDevelopmentMode;
+
+               if ( !self::canBeGlobal( $title ) ) {
+                       return false;
+               }
+
+               // Do some instance caching since this can be
+               // called frequently due do the Linker hook
+               if ( !self::$displayCache ) {
+                       self::$displayCache = new MapCacheLRU( 100 );
+               }
+
+               $text = $title->getPrefixedText();
+               if ( self::$displayCache->has( $text ) ) {
+                       return self::$displayCache->get( $text );
+               }
+
+               // If we're running in development mode, skip the page 
existence check.
+               // It can be a bit of a problem when your local copy of the Hub 
DB is
+               // *not* 100% up to date (e.g. a page exists on Hub but not on 
your local
+               // copy of Hub's DB).
+               if ( $wgSharedHelpPagesDevelopmentMode ) {
+                       return true;
+               } else {
+                       $touched = (bool)self::getCentralTouched( $title );
+                       self::$displayCache->set( $text, $touched );
+                       return $touched;
+               }
+       }
+
+       /**
+        * Get the page_touched of the shared help page
+        *
+        * @todo this probably shouldn't be static
+        * @param Title $title
+        * @return string|bool
+        */
+       protected static function getCentralTouched( Title $title ) {
+               if ( !self::$touchedCache ) {
+                       self::$touchedCache = new MapCacheLRU( 100 );
+               }
+               if ( self::$touchedCache->has( $title->getDBkey() ) ) {
+                       return self::$touchedCache->get( $title->getDBkey() );
+               }
+
+               $sharedHelpDB = SharedHelpPagesHooks::determineDatabase();
+               $lb = wfGetLB( $sharedHelpDB );
+               $dbr = $lb->getConnectionRef( DB_REPLICA, [], $sharedHelpDB );
+               $row = $dbr->selectRow(
+                       [ 'page' ],
+                       [ 'page_touched' ],
+                       [
+                               'page_namespace' => NS_HELP,
+                               'page_title' => $title->getDBkey(),
+                       ],
+                       __METHOD__
+               );
+               if ( $row ) {
+                       $touched = $row->page_touched;
+               } else {
+                       $touched = false;
+               }
+
+               self::$touchedCache->set( $title->getDBkey(), $touched );
+
+               return $touched;
+       }
+
+       /**
+        * Given a Title, is it a source page we might
+        * be "transcluding" on another site
+        *
+        * @return bool
+        */
+       public function isSourcePage() {
+               if ( wfWikiID() !== SharedHelpPagesHooks::determineDatabase() ) 
{
+                       return false;
+               }
+
+               $title = $this->getTitle();
+               if ( !$title->inNamespace( NS_HELP ) ) {
+                       return false;
+               }
+
+               // Root help page
+               return $title->getRootTitle()->equals( $title );
+       }
+
+       /**
+        * @param string $touched The page_touched for the page
+        * @return array
+        */
+       public function getRemoteParsedText( $touched ) {
+               $langCode = $this->getContext()->getLanguage()->getCode();
+
+               // Need language code in the key since we pass &uselang= to the 
API.
+               $key = $this->cache->makeGlobalKey( 'sharedhelppages', 'parsed',
+                       self::PARSED_CACHE_VERSION, $touched, $langCode, md5( 
$this->mPage->getTitle()->getPrefixedText() )
+               );
+               $data = $this->cache->get( $key );
+               if ( $data === false ) {
+                       $data = $this->parseWikiText( $this->getTitle(), 
$langCode );
+                       if ( $data ) {
+                               $this->cache->set( $key, $data, 
$this->config->get( 'SharedHelpPagesCacheExpiry' ) );
+                       } else {
+                               // Cache failure for 10 seconds
+                               $this->cache->set( $key, null, 10 );
+                       }
+               }
+
+               return $data;
+       }
+
+       /**
+        * Checks whether the given page can be global
+        * doesn't check the actual database
+        *
+        * @param Title $title
+        * @return bool
+        */
+       protected static function canBeGlobal( Title $title ) {
+               // Don't run this code for Hub.
+               if ( wfWikiID() === SharedHelpPagesHooks::determineDatabase() ) 
{
+                       return false;
+               }
+
+               // Must be a help page
+               if ( !$title->inNamespace( NS_HELP ) ) {
+                       return false;
+               }
+
+               // Why not?
+               return true;
+       }
+
+       /**
+        * @param Title $title
+        * @return SharedHelpPagePage
+        */
+       public function newPage( Title $title ) {
+               return new SharedHelpPagePage( $title, $this->config );
+       }
+
+       /**
+        * Use action=parse to get rendered HTML of a page
+        *
+        * @param Title $title
+        * @param string $langCode
+        * @return array|bool
+        */
+       protected function parseWikiText( Title $title, $langCode ) {
+               $unLocalizedName = MWNamespace::getCanonicalName( NS_HELP ) . 
':' . $title->getText();
+               $wikitext = '{{:' . $unLocalizedName . '}}';
+               $params = [
+                       'action' => 'parse',
+                       'title' => $unLocalizedName,
+                       'text' => $wikitext,
+                       'disableeditsection' => 1,
+                       'disablelimitreport' => 1,
+                       'prop' => 'text|modules|jsconfigvars',
+                       'formatversion' => 2
+               ];
+               $data = $this->mPage->makeAPIRequest( $params, $langCode );
+               $parsed = $data['parse'];
+
+               if ( $this->config->get( 'SharedHelpPagesDevelopmentMode' ) ) {
+                       // XXX FILTHY HACK!
+                       // Replace the remote wiki's script path with ours
+                       // My local URLs look like this: 
http://localhost/shoutwiki/trunk/index.php/Help:Links
+                       // Whereas production URLs look like this: 
http://www.shoutwiki.com/wiki/Help:Links
+                       // So this is really needed only for devboxes etc.
+                       global $wgArticlePath;
+                       $parsed['text'] = preg_replace( '/href="\/wiki\//', 
'href="' . str_replace( '$1', '', $wgArticlePath ), $parsed['text'] );
+               }
+
+               // HACK TIME! The parsed wikitext acts as if it was parsed on 
the remote
+               // wiki -- this is good for things like images and whatnot, but 
very
+               // bad for things like the project namespace name and whatnot.
+               // So, we need to get the remote wiki's project (&project talk) 
NS names;
+               // either from memcached, or failing that, via an API query.
+               global $wgContLang, $wgLanguageCode, $wgMemc;
+
+               $projectNSCacheKey = wfMemcKey( 'helppages', $wgLanguageCode, 
'projectns' );
+               $projectTalkNSCacheKey = wfMemcKey( 'helppages', 
$wgLanguageCode, 'projecttalkns' );
+
+               $remoteWikiProjectNS = $wgMemc->get( $projectNSCacheKey );
+               $remoteWikiProjectTalkNS = $wgMemc->get( $projectTalkNSCacheKey 
);
+
+               if (
+                       $remoteWikiProjectNS === false ||
+                       $remoteWikiProjectTalkNS === false
+               )
+               {
+                       // Damn, no cache hit, so we need to hit the API 
instead.
+                       // Yes, I realize that's a terrible pun.
+                       $nsQueryParams = array(
+                               'action' => 'query',
+                               'meta' => 'siteinfo',
+                               'siprop' => 'namespaces|namespacealiases'
+                       );
+                       $namespaceData = $this->mPage->makeAPIRequest( 
$nsQueryParams, $langCode );
+
+                       // Get the remote wiki's NS_PROJECT & NS_PROJECT_TALK
+                       $remoteWikiProjectNS = 
$namespaceData['query']['namespaces'][NS_PROJECT]['*'];
+                       $remoteWikiProjectTalkNS = 
$namespaceData['query']['namespaces'][NS_PROJECT_TALK]['*'];
+
+                       // Sanitize it. This should have the nice side-effect 
of avoiding (too many)
+                       // false positives since about the only place where 
underscores are used
+                       // in namespace names are, unsurprisingly, URLs. :)
+                       $remoteWikiProjectNS = str_replace( ' ', '_', 
$remoteWikiProjectNS );
+                       $remoteWikiProjectTalkNS = str_replace( ' ', '_', 
$remoteWikiProjectTalkNS );
+
+                       // Store both values in memcached for a week, since 
namespace names
+                       // (especially on Hub(s)) are unlikely to change very 
often
+                       $wgMemc->set( $projectNSCacheKey, $remoteWikiProjectNS, 
7 * 86400 );
+                       $wgMemc->set( $projectTalkNSCacheKey, 
$remoteWikiProjectTalkNS, 7 * 86400 );
+               }
+
+               $parsed = str_replace(
+                       array(
+                               $remoteWikiProjectNS . ':',
+                               $remoteWikiProjectTalkNS . ':',
+                       ),
+                       array(
+                               $wgContLang->getNsText( NS_PROJECT ) . ':',
+                               $wgContLang->getNsText( NS_PROJECT_TALK ) . ':',
+                       ),
+                       $parsed
+               );
+
+               return $data !== false ? $parsed : false;
+       }
+
+       /**
+        * @return array
+        */
+       public static function getEnabledWikis() {
+               static $list = null;
+               if ( $list === null ) {
+                       $list = [];
+                       if ( Hooks::run( 'SharedHelpPagesWikis', [ &$list ] ) ) 
{
+                               // Fallback if no hook override
+                               global $wgLocalDatabases;
+                               $list = $wgLocalDatabases;
+                       }
+               }
+
+               return $list;
+       }
+}
diff --git a/SharedHelpPageCacheInvalidator.php 
b/SharedHelpPageCacheInvalidator.php
new file mode 100644
index 0000000..7031547
--- /dev/null
+++ b/SharedHelpPageCacheInvalidator.php
@@ -0,0 +1,39 @@
+<?php
+
+class SharedHelpPageCacheInvalidator {
+       /**
+        * Page name of the page whose cache needs to be invalidated
+        *
+        * @var string
+        */
+       private $pagename;
+
+       /**
+        * Array of string options
+        *
+        * @var array
+        */
+       private $options;
+
+       public function __construct( $pagename, array $options = [] ) {
+               $this->pagename = $pagename;
+               $this->options = $options;
+       }
+
+       public function invalidate() {
+               global $wgUseSquid, $wgUseFileCache;
+
+               if ( !$wgUseSquid && !$wgUseFileCache && !$this->options ) {
+                       // No Squid and no options means nothing to do!
+                       return;
+               }
+
+               JobQueueGroup::singleton()->push( new 
SharedHelpPageLocalJobSubmitJob(
+                       Title::newFromText( 'Help:' . $this->pagename ),
+                       [
+                               'pagename' => $this->pagename,
+                               'touch' => in_array( 'links', $this->options ),
+                       ]
+               ) );
+       }
+}
diff --git a/SharedHelpPageLocalJobSubmitJob.php 
b/SharedHelpPageLocalJobSubmitJob.php
new file mode 100644
index 0000000..a7aeaad
--- /dev/null
+++ b/SharedHelpPageLocalJobSubmitJob.php
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * Job class that submits LocalSharedHelpPageCacheUpdateJob jobs
+ */
+class SharedHelpPageLocalJobSubmitJob extends Job {
+       public function __construct( Title $title, array $params ) {
+               parent::__construct( 'SharedHelpPageLocalJobSubmitJob', $title, 
$params );
+       }
+
+       public function run() {
+               $job = new LocalSharedHelpPageCacheUpdateJob(
+                       Title::newFromText( 'Help:' . $this->params['pagename'] 
),
+                       $this->params
+               );
+               foreach ( SharedHelpPages::getEnabledWikis() as $wiki ) {
+                       JobQueueGroup::singleton( $wiki )->push( $job );
+               }
+       }
+}
diff --git a/SharedHelpPagePage.php b/SharedHelpPagePage.php
new file mode 100644
index 0000000..34306f1
--- /dev/null
+++ b/SharedHelpPagePage.php
@@ -0,0 +1,128 @@
+<?php
+
+class SharedHelpPagePage extends WikiPage {
+
+       /**
+        * @var Config
+        */
+       private $config;
+
+       /**
+        * @var BagOStuff
+        */
+       private $cache;
+
+       public function __construct( Title $title, Config $config ) {
+               global $wgMemc;
+               parent::__construct( $title );
+               $this->config = $config;
+               $this->cache = $wgMemc;
+       }
+
+       public function isLocal() {
+               return $this->getTitle()->exists();
+       }
+
+       /**
+        * @return string
+        */
+       public function getWikiDisplayName() {
+               $url = $this->getSourceURL();
+               return wfParseUrl( $url )['host'];
+       }
+
+       /**
+        * Page name for the given shared help page
+        *
+        * @return string
+        */
+       public function getPagename() {
+               return $this->getTitle()->getText();
+       }
+
+       /**
+        * Returns a URL to the help page on the central wiki,
+        * attempts to use SiteConfiguration if possible, else
+        * falls back to using an API request
+        *
+        * @return string
+        */
+       public function getSourceURL() {
+               $wiki = WikiMap::getWiki( 
SharedHelpPagesHooks::determineDatabase() );
+               if ( $wiki ) {
+                       return $wiki->getCanonicalUrl(
+                               'Help:' . $this->getPagename()
+                       );
+               }
+
+               // Fallback to the API
+               return $this->getRemoteURLFromAPI();
+       }
+
+       /**
+        * Returns a URL to the help page on the central wiki;
+        * if MW >= 1.24, this will be the canonical URL, otherwise
+        * it will be using whatever protocol was specified in
+        * $wgSharedHelpPagesAPIUrl.
+        *
+        * @return string
+        */
+       protected function getRemoteURLFromAPI() {
+               $key = 'sharedhelppages:url:' . md5( $this->getPagename() );
+               $data = $this->cache->get( $key );
+               if ( $data === false ) {
+                       $params = [
+                               'action' => 'query',
+                               'titles' => 'Help:' . $this->getPagename(),
+                               'prop' => 'info',
+                               'inprop' => 'url',
+                               'formatversion' => '2',
+                       ];
+                       $resp = $this->makeAPIRequest( $params );
+                       if ( $resp === false ) {
+                               // Don't cache upon failure
+                               return '';
+                       }
+                       $data = $resp['query']['pages'][0]['canonicalurl'];
+                       // Don't set an expiry since we expect people not to 
change the
+                       // URL to their wiki without clearing their caches!
+                       $this->cache->set( $key, $data );
+               }
+
+               return $data;
+       }
+
+       /**
+        * Makes an API request to the central wiki
+        *
+        * @param $params array
+        * @param string $langCode ISO 639 language code, used to select the 
correct URL
+        * @return array|bool false if the request failed
+        */
+       public function makeAPIRequest( $params, $langCode = 'en' ) {
+               $params['format'] = 'json';
+
+               if ( in_array( $langCode, $this->config->get( 
'SharedHelpLanguages' ) ) && $langCode != 'en' ) {
+                       $baseURL = 
"http://{$langCode}.shoutwiki.com/w/api.php";; // @todo FIXME: move to config, I 
guess
+               } else {
+                       // Fall back to English
+                       $baseURL = $this->config->get( 'SharedHelpPagesAPIUrl' 
);
+               }
+
+               $url = wfAppendQuery( $baseURL, $params );
+
+               wfDebugLog( 'SharedHelpPages', "Making a request to $url" );
+               $req = MWHttpRequest::factory(
+                       $url,
+                       [ 'timeout' => $this->config->get( 
'SharedHelpPagesTimeout' ) ]
+               );
+               $status = $req->execute();
+               if ( !$status->isOK() ) {
+                       wfDebugLog( 'SharedHelpPages', __METHOD__ . " Error: 
{$status->getWikitext()}" );
+                       return false;
+               }
+               $json = $req->getContent();
+               $decoded = FormatJson::decode( $json, true );
+               return $decoded;
+       }
+}
diff --git a/SharedHelpPages.body.php b/SharedHelpPages.body.php
deleted file mode 100644
index a1cee04..0000000
--- a/SharedHelpPages.body.php
+++ /dev/null
@@ -1,221 +0,0 @@
-<?php
-
-class SharedHelpPages {
-
-       /**
-        * Makes an API request to ShoutWiki Hub
-        *
-        * @param $params array
-        * @param $langCode string
-        * @return array
-        */
-       public static function makeAPIRequest( $params, $langCode ) {
-               global $wgSharedHelpLanguages;
-
-               $params['format'] = 'json';
-
-               if ( in_array( $langCode, $wgSharedHelpLanguages ) && $langCode 
!= 'en' ) {
-                       $baseURL = "http://{$langCode}.shoutwiki.com/w/api.php";;
-               } else {
-                       // Fall back to English
-                       $baseURL = 'http://www.shoutwiki.com/w/api.php';
-               }
-               $url = wfAppendQuery( $baseURL, $params );
-
-               $req = MWHttpRequest::factory( $url );
-               $req->execute();
-               $json = $req->getContent();
-               $decoded = FormatJson::decode( $json, true );
-               return $decoded;
-       }
-
-       /**
-        * Get the cache key for a certain title
-        *
-        * @param Title|string $title
-        * @return string
-        */
-       public static function getCacheKey( $title ) {
-               global $wgLanguageCode;
-               return wfMemcKey( 'helppages', $wgLanguageCode, md5( $title ), 
'v2' );
-       }
-
-       /**
-        * Use action=parse to get rendered HTML of a page
-        *
-        * @param $title string
-        * @param $langCode string
-        * @return array
-        */
-       public static function parseWikiText( $title, $langCode ) {
-               $params = array(
-                       'action' => 'parse',
-                       'page' => $title,
-                       'redirects' => true // follow redirects
-               );
-               $data = self::makeAPIRequest( $params, $langCode );
-               $parsed = $data['parse']['text']['*'];
-               $oldid = $data['parse']['revid'];
-
-               // Eliminate section edit links
-               // As legoktm pointed out, this is done in CSS, which works and 
most
-               // likely is a lot faster, but I'll keep this around anyway for 
future
-               // reference.
-               /*
-               $parsed = preg_replace(
-                       "/<span class=\"mw-editsection\"><span 
class=\"mw-editsection-bracket\">(.*?)<\/span><a .*?>(.*?)<\/a>\<span 
class=\"mw-editsection-bracket\">(.*?)<\/span><\/span>/",
-                       '',
-                       $parsed
-               );
-               */
-
-               // HACK TIME! The parsed wikitext acts as if it was parsed on 
the remote
-               // wiki -- this is good for things like images and whatnot, but 
very
-               // bad for things like the project namespace name and whatnot.
-               // So, we need to get the remote wiki's project (&project talk) 
NS names;
-               // either from memcached, or failing that, via an API query.
-               global $wgContLang, $wgLanguageCode, $wgMemc;
-
-               $projectNSCacheKey = wfMemcKey( 'helppages', $wgLanguageCode, 
'projectns' );
-               $projectTalkNSCacheKey = wfMemcKey( 'helppages', 
$wgLanguageCode, 'projecttalkns' );
-
-               $remoteWikiProjectNS = $wgMemc->get( $projectNSCacheKey );
-               $remoteWikiProjectTalkNS = $wgMemc->get( $projectTalkNSCacheKey 
);
-
-               if (
-                       $remoteWikiProjectNS === false ||
-                       $remoteWikiProjectTalkNS === false
-               )
-               {
-                       // Damn, no cache hit, so we need to hit the API 
instead.
-                       // Yes, I realize that's a terrible pun.
-                       $nsQueryParams = array(
-                               'action' => 'query',
-                               'meta' => 'siteinfo',
-                               'siprop' => 'namespaces|namespacealiases'
-                       );
-                       $namespaceData = self::makeAPIRequest( $nsQueryParams, 
$langCode );
-
-                       // Get the remote wiki's NS_PROJECT & NS_PROJECT_TALK
-                       $remoteWikiProjectNS = 
$namespaceData['query']['namespaces'][NS_PROJECT]['*'];
-                       $remoteWikiProjectTalkNS = 
$namespaceData['query']['namespaces'][NS_PROJECT_TALK]['*'];
-
-                       // Sanitize it. This should have the nice side-effect 
of avoiding (too many)
-                       // false positives since about the only place where 
underscores are used
-                       // in namespace names are, unsurprisingly, URLs. :)
-                       $remoteWikiProjectNS = str_replace( ' ', '_', 
$remoteWikiProjectNS );
-                       $remoteWikiProjectTalkNS = str_replace( ' ', '_', 
$remoteWikiProjectTalkNS );
-
-                       // Store both values in memcached for a week, since 
namespace names
-                       // (especially on Hub(s)) are unlikely to change very 
often
-                       $wgMemc->set( $projectNSCacheKey, $remoteWikiProjectNS, 
7 * 86400 );
-                       $wgMemc->set( $projectTalkNSCacheKey, 
$remoteWikiProjectTalkNS, 7 * 86400 );
-               }
-
-               $parsed = str_replace(
-                       array(
-                               $remoteWikiProjectNS . ':',
-                               $remoteWikiProjectTalkNS . ':',
-                       ),
-                       array(
-                               $wgContLang->getNsText( NS_PROJECT ) . ':',
-                               $wgContLang->getNsText( NS_PROJECT_TALK ) . ':',
-                       ),
-                       $parsed
-               );
-
-               return array( $parsed, $oldid );
-       }
-
-       /**
-        * Get the page text in the content language or a fallback
-        *
-        * @param $title string page name
-        * @return string|bool false if couldn't be found
-        */
-       public static function getPagePlusFallbacks( $title ) {
-               global $wgContLang, $wgLanguageCode, $wgMemc, 
$wgSharedHelpPagesExpiry;
-
-               $title = str_replace( 'Help:', $wgContLang->getNsText( NS_HELP 
) . ':', $title );
-
-               $key = self::getCacheKey( $title );
-               $cached = $wgMemc->get( $key );
-
-               if ( $cached !== false ) {
-                       return $cached;
-               }
-
-               $titles = array();
-
-               $titles[$title] = $wgLanguageCode;
-
-               $params = array(
-                       'action' => 'query',
-                       'titles' => implode( '|', array_keys( $titles ) )
-               );
-               $data = self::makeAPIRequest( $params, $wgLanguageCode );
-               $pages = array();
-
-               foreach ( $data['query']['pages'] as /* $id => */ $info ) {
-                       if ( isset( $info['missing'] ) ) {
-                               continue;
-                       }
-                       $lang = $titles[$info['title']];
-                       $pages[$lang] = $info['title'];
-               }
-
-               if ( isset( $pages[$wgLanguageCode] ) ) {
-                       $html = self::parseWikiText( $pages[$wgLanguageCode], 
$wgLanguageCode );
-                       $wgMemc->set( $key, $html, $wgSharedHelpPagesExpiry );
-                       return $html;
-               }
-
-
-               return false;
-       }
-
-       /**
-        * Determine the proper help wiki database, based on current wiki's
-        * language code.
-        *
-        * By default this is assumed to follow the languagecode_wiki format.
-        * Exceptions to this rule are:
-        * 1) English and all of its variants, which fall back to the shoutwiki 
DB
-        * 2) Language is not in the $wgSharedHelpLanguages array --> shoutwiki 
DB
-        *
-        * @return Mixed: database name (string) normally, boolean true on the 
help
-        *                wiki
-        */
-       public static function determineDatabase() {
-               global $wgLanguageCode, $wgSharedHelpLanguages;
-
-               if ( in_array( $wgLanguageCode, $wgSharedHelpLanguages ) && 
$wgLanguageCode !== 'en' ) {
-                       $helpDBname = "{$wgLanguageCode}_wiki";
-               } elseif ( in_array( $wgLanguageCode, array( 'en', 'en-gb', 
'en-ca' ) ) ) {
-                       $helpDBname = 'shoutwiki';
-               } else {
-                       // fall back to English help
-                       $helpDBname = 'shoutwiki';
-               }
-
-               return $helpDBname;
-       }
-
-       /**
-        * Is SharedHelpPages available for the current wiki's language (code)?
-        *
-        * @param $langCode String: language code
-        * @return Boolean: true if it's available, otherwise false
-        */
-       public static function isSupportedLanguage() {
-               global $wgLanguageCode, $wgSharedHelpLanguages;
-
-               $isEnglish = in_array( $wgLanguageCode, array( 'en', 'en-gb', 
'en-ca' ) );
-
-               if ( in_array( $wgLanguageCode, $wgSharedHelpLanguages ) || 
$isEnglish ) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-}
diff --git a/SharedHelpPages.hooks.php b/SharedHelpPages.hooks.php
index 692b517..c95771f 100644
--- a/SharedHelpPages.hooks.php
+++ b/SharedHelpPages.hooks.php
@@ -1,39 +1,95 @@
 <?php
 
 class SharedHelpPagesHooks {
+
        /**
-        * @param $article Article
+        * @param Title $title
+        * @param Article|null $page
+        * @param IContextSource $context
         * @return bool
         */
-       public static function onShowMissingArticle( $article ) {
-               $context = $article->getContext();
-               $output = $context->getOutput();
-               $title = $article->getTitle();
-
-               if ( $title->getNamespace() == NS_HELP ) {
-                       global $wgDBname;
-
-                       $sharedHelpDBname = 
SharedHelpPages::determineDatabase();
-
-                       // Don't run this code on the source wiki of the shared 
help pages.
-                       // Also don't run this code if SharedHelpPages isn't 
enabled for the
-                       // current wiki's language (for performance reasons).
-                       if ( $wgDBname == $sharedHelpDBname || 
!SharedHelpPages::isSupportedLanguage() ) {
-                               return true;
-                       }
-
-                       list( $text, $oldid ) = 
SharedHelpPages::getPagePlusFallbacks( 'Help:' . $title->getText() );
-                       if ( $text ) {
-                               // Add a notice indicating that it was taken 
from ShoutWiki Hub
-                               // noticed moved to the EditPage hook --ashley, 
24 December 2013
-                               //$output->addHTML( $context->msg( 
'sharedhelppages-notice', $oldid )->parse() );
-                               $output->addHTML( $text );
-                               // Hide the "this page does not exist" notice 
and edit section links
-                               $output->addModuleStyles( 'ext.SharedHelpPages' 
);
-                       }
+       public static function onArticleFromTitle( Title &$title, &$page, 
$context ) {
+               // If another extension's hook has already run, don't override 
it
+               if ( $page === null
+                       && $title->inNamespace( NS_HELP ) && !$title->exists()
+                       && SharedHelpPage::shouldDisplaySharedPage( $title )
+               ) {
+                       $page = new SharedHelpPage(
+                               $title,
+                               
ConfigFactory::getDefaultInstance()->makeConfig( 'sharedhelppages' )
+                       );
                }
 
                return true;
+       }
+
+       /**
+        * Mark shared help pages as known so they appear in blue
+        *
+        * @param Title $title Title to check
+        * @param bool &$isKnown Whether the page should be considered known
+        * @return bool
+        */
+       public static function onTitleIsAlwaysKnown( $title, &$isKnown ) {
+               if ( SharedHelpPage::shouldDisplaySharedPage( $title ) ) {
+                       $isKnown = true;
+               }
+
+               return true;
+       }
+
+       /**
+        * Whether a page is a shared help page on the Hub wiki
+        *
+        * @param Title $title
+        * @return bool
+        */
+       protected static function isSharedHelpPage( Title $title ) {
+               return self::determineDatabase() === wfWikiID() // On the Hub 
wiki
+                       && $title->inNamespace( NS_HELP ); // is a help page.
+       }
+
+       /**
+        * After a LinksUpdate runs for a help page, queue remote Squid purges
+        *
+        * @param LinksUpdate $lu
+        * @return bool
+        */
+       public static function onLinksUpdateComplete( LinksUpdate &$lu ) {
+               $title = $lu->getTitle();
+               if ( self::isSharedHelpPage( $title ) ) {
+                       $inv = new SharedHelpPageCacheInvalidator( 
$title->getText() );
+                       $inv->invalidate();
+               }
+
+               return true;
+       }
+
+       /**
+        * Invalidate cache on remote wikis when a new page is created
+        * Also handles the ArticleDeleteComplete hook
+        *
+        * @param WikiPage $page
+        * @return bool
+        */
+       public static function onPageContentInsertComplete( WikiPage $page ) {
+               $title = $page->getTitle();
+               if ( self::isSharedHelpPage( $title ) ) {
+                       $inv = new SharedHelpPageCacheInvalidator( 
$title->getText(), [ 'links' ] );
+                       $inv->invalidate();
+               }
+
+               return true;
+       }
+
+       /**
+        * Invalidate cache on remote wikis when a shared help page is deleted
+        *
+        * @param WikiPage $page
+        * @return bool
+        */
+       public static function onArticleDeleteComplete( WikiPage $page ) {
+               return self::onPageContentInsertComplete( $page );
        }
 
        /**
@@ -44,61 +100,33 @@
         * This function originally changed the "edit" links to point to a 
different
         * wiki for pages in the Help: namespace.
         *
-        * @param SkinTemplate $sktemplate
+        * @param SkinTemplate $skTemplate
         * @param array $links
         * @return bool
         */
-       public static function onSkinTemplateNavigationUniversal( &$sktemplate, 
&$links ) {
-               $context = $sktemplate->getContext();
-               $title = $sktemplate->getTitle();
+       public static function onSkinTemplateNavigationUniversal( &$skTemplate, 
&$links ) {
+               $title = $skTemplate->getTitle();
 
-               if ( $title->getNamespace() == NS_HELP ) {
-                       global $wgDBname;
-
-                       $sharedHelpDBname = 
SharedHelpPages::determineDatabase();
-
+               if ( $title->inNamespace( NS_HELP ) ) {
                        // Don't run this code on the source wiki of the shared 
help pages.
                        // Also don't run this code if SharedHelpPages isn't 
enabled for the
                        // current wiki's language.
-                       if ( $wgDBname == $sharedHelpDBname || 
!SharedHelpPages::isSupportedLanguage() ) {
+                       if ( self::determineDatabase() === wfWikiID() || 
!self::isSupportedLanguage() ) {
                                return true;
                        }
 
-                       list( $text, $oldid ) = 
SharedHelpPages::getPagePlusFallbacks( 'Help:' . $title->getText() );
-                       if ( $text ) {
-                               /*
-                               global $wgLanguageCode, $wgSharedHelpLanguages;
-
-                               // Determine the correct subdomain
-                               if (
-                                       in_array( $wgLanguageCode, 
$wgSharedHelpLanguages ) &&
-                                       !in_array( $wgLanguageCode, array( 
'en', 'en-gb', 'en-ca' ) )
-                               )
-                               {
-                                       $langCode = $wgLanguageCode;
-                               } else {
-                                       $langCode = 'www';
-                               }
-                               */
+                       if ( SharedHelpPage::shouldDisplaySharedPage( $title ) 
) {
+                               // This removes the additional "View on 
www.shoutwiki.com" tab/
+                               // link from the content actions array on Help: 
pages
+                               unset( $links['views']['view-foreign'] );
+                               // And this changes the edit tab's(/link's) 
text back to "Create"
+                               // from "Add local description" (which is just 
plain wtf as that
+                               // string literally makes no sense for any 
other context than
+                               // foreign _file_ pages)
+                               $links['views']['edit']['text'] = 
$skTemplate->msg( 'create' )->text();
 
                                $links['namespaces']['help']['class'] = 
'selected';
                                $links['namespaces']['help']['href'] = 
$title->getFullURL();
-                               /*
-                               $links['namespaces']['help_talk']['class'] = '';
-                               $links['namespaces']['help_talk']['href'] = 
"http://{$langCode}.shoutwiki.com/wiki/Help_talk:"; . $title->getText();
-                               $links['views'] = array(); // Kill the 'Create' 
button @todo make this suck less
-                               $links['views'][] = array(
-                                       'class' => false,
-                                       'text' => $context->msg( 
'sharedhelppages-edit-tab' ),
-                                       'href' => wfAppendQuery(
-                                               
"http://{$langCode}.shoutwiki.com/w/index.php";,
-                                               array(
-                                                       'action' => 'edit',
-                                                       'title' => 
$title->getPrefixedText()
-                                               )
-                                       )
-                               );
-                               */
                        }
                }
 
@@ -106,91 +134,17 @@
        }
 
        /**
-        * Use action=purge to clear cache
-        *
-        * @param $article Article
+        * @param Title $title
+        * @param $page
         * @return bool
         */
-       public static function onArticlePurge( &$article ) {
-               global $wgMemc;
-
-               $title = $article->getContext()->getTitle();
-               $key = SharedHelpPages::getCacheKey( $title );
-               $wgMemc->delete( $key );
-
-               return true;
-       }
-
-       /**
-        * Turn red Help: links into blue ones
-        *
-        * @param $linker
-        * @param $target Title
-        * @param $text String
-        * @param $customAtrribs Array: array of custom attributes [unused]
-        * @param $query [unused]
-        * @param $ret String: return value (link HTML)
-        * @return Boolean
-        */
-       public static function brokenLink( $linker, $target, &$text, 
&$customAttribs, &$query, &$options, &$ret ) {
-               global $wgDBname;
-
-               $sharedHelpDBname = SharedHelpPages::determineDatabase();
-
-               // Don't run this code on the source wiki of the shared help 
pages.
-               // Also don't run this code if SharedHelpPages isn't enabled 
for the
-               // current wiki's language.
-               if ( $wgDBname == $sharedHelpDBname || 
!SharedHelpPages::isSupportedLanguage() ) {
-                       return true;
-               }
-
-               if ( $target->getNamespace() == NS_HELP ) {
-                       // return immediately if we know it's real
-                       // this part "borrowed" from ^demon's RemoveRedlinks, 
dunno if
-                       // we really need it anymore, but idk
-                       if ( in_array( 'known', $options ) || 
$target->isKnown() ) {
-                               return true;
-                       } else {
-                               $ret = Linker::linkKnown( $target, $text );
-                               return false;
-                       }
-               }
-
-               return true;
-       }
-
-       /**
-        * Shows a warning-ish message on &action=edit whenever a user tries to
-        * edit a shared help page
-        *
-        * @param $editPage EditPage
-        * @return Boolean: true
-        */
-       public static function displayMessageOnEditPage( &$editPage ) {
-               global $wgDBname;
-
-               $title = $editPage->getTitle();
-
-               // do not show this message on the help wiki
-               // Also don't run this code if SharedHelpPages isn't enabled 
for the
-               // current wiki's language.
-               if ( $wgDBname == SharedHelpPages::determineDatabase() || 
!SharedHelpPages::isSupportedLanguage() ) {
-                       return true;
-               }
-
-               // show message only when editing pages from Help namespace
-               if ( $title->getNamespace() != 12 ) {
-                       return true;
-               }
-
-               list( $text, $oldid ) = SharedHelpPages::getPagePlusFallbacks( 
'Help:' . $title->getText() );
-               if ( $text ) {
-                       // Add a notice indicating that the content was 
originally taken from ShoutWiki Hub
-                       $msg = '<div style="border: solid 1px; padding: 10px; 
margin: 5px" class="sharedHelpEditInfo">';
-                       $msg .= wfMessage( 'sharedhelppages-notice', $oldid 
)->parse();
-                       $msg .= '</div>';
-
-                       $editPage->editFormPageTop .= $msg;
+       public static function onWikiPageFactory( Title $title, &$page ) {
+               if ( SharedHelpPage::shouldDisplaySharedPage( $title ) ) {
+                       $page = new SharedHelpPagePage(
+                               $title,
+                               
ConfigFactory::getDefaultInstance()->makeConfig( 'sharedhelppages' )
+                       );
+                       return false;
                }
 
                return true;
@@ -202,19 +156,19 @@
         *
         * Hooked into the WantedPages::getQueryInfo hook.
         *
-        * @param $wantedPagesPage WantedPagesPage
-        * @param $array Array: SQL query conditions
-        * @return Boolean: true
+        * @param WantedPagesPage $wantedPagesPage
+        * @param array $array SQL query conditions
+        * @return bool
         */
        public static function modifyWantedPagesSQL( $wantedPagesPage, $query ) 
{
                global $wgDBname;
 
-               $sharedHelpDBname = SharedHelpPages::determineDatabase();
+               $sharedHelpDBname = self::determineDatabase();
 
                // Don't run this code on the source wiki of the shared help 
pages.
                // Also don't run this code if SharedHelpPages isn't enabled 
for the
                // current wiki's language.
-               if ( $wgDBname == $sharedHelpDBname || 
!SharedHelpPages::isSupportedLanguage() ) {
+               if ( $wgDBname == $sharedHelpDBname || 
!self::isSupportedLanguage() ) {
                        return true;
                }
 
@@ -228,6 +182,43 @@
                                'pl_title = pg3.page_title'
                        )
                );
+
+               return true;
+       }
+
+       /**
+        * Shows a warning-ish message on &action=edit whenever a user tries to
+        * edit a shared help page
+        *
+        * @param EditPage $editPage
+        * @return bool
+        */
+       public static function displayMessageOnEditPage( &$editPage ) {
+               global $wgDBname;
+
+               $title = $editPage->getTitle();
+
+               // do not show this message on the help wiki
+               // Also don't run this code if SharedHelpPages isn't enabled 
for the
+               // current wiki's language.
+               if ( $wgDBname == self::determineDatabase() || 
!self::isSupportedLanguage() ) {
+                       return true;
+               }
+
+               // show message only when editing pages from Help namespace
+               if ( !$title->inNamespace( NS_HELP ) ) {
+                       return true;
+               }
+
+               if ( SharedHelpPage::shouldDisplaySharedPage( $title ) ) {
+                       // Add a notice indicating that the content was 
originally taken from ShoutWiki Hub
+                       $msg = '<div style="border: solid 1px; padding: 10px; 
margin: 5px" class="sharedHelpEditInfo">';
+                       $msg .= wfMessage( 'sharedhelppages-notice', 
$title->getPrefixedText() )->parse();
+                       $msg .= '</div>';
+
+                       $editPage->editFormPageTop .= $msg;
+               }
+
                return true;
        }
 
@@ -238,27 +229,70 @@
         * This enables the display of "Content is available under <license>" 
message
         * in the page footer instead of only the copyright icon being 
displayed.
         *
-        * @param $skTpl SkinTemplate
-        * @param $tpl A subclass of SkinTemplate, i.e. for Monobook it'd be 
MonobookTemplate
-        * @return Boolean
+        * @param SkinTemplate $skTpl
+        * @param SkinTemplate|MonoBookTemplate|VectorTemplate|... $tpl A 
subclass of SkinTemplate, i.e. for MonoBook it'd be MonoBookTemplate
+        * @return bool
         */
        public static function onSkinTemplateOutputPageBeforeExec( &$skTpl, 
&$tpl ) {
                global $wgDBname;
 
-               $sharedHelpDBname = SharedHelpPages::determineDatabase();
+               $sharedHelpDBname = self::determineDatabase();
 
                // Don't run this code on the source wiki of the shared help 
pages.
                // Also don't run this code if SharedHelpPages isn't enabled 
for the
                // current wiki's language.
-               if ( $wgDBname == $sharedHelpDBname || 
!SharedHelpPages::isSupportedLanguage() ) {
+               if ( $wgDBname == $sharedHelpDBname || 
!self::isSupportedLanguage() ) {
                        return true;
                }
 
                $title = $skTpl->getTitle();
-               if ( $title->getNamespace() == NS_HELP ) {
+               if ( $title->inNamespace( NS_HELP ) ) {
                        $tpl->set( 'copyright', $skTpl->getCopyright() );
                }
 
                return true;
        }
+
+       // UTILITY METHODS WHICH ARE NOT HOOKED FUNCTIONS THEMSELVES //
+
+       /**
+        * Determine the proper help wiki database, based on current wiki's
+        * language code.
+        *
+        * By default this is assumed to follow the languagecode_wiki format.
+        * Exceptions to this rule are:
+        * 1) English and all of its variants, which fall back to the shoutwiki 
DB
+        * 2) Language is not in the $wgSharedHelpLanguages array --> shoutwiki 
DB
+        *
+        * @return string|bool Database name (string) normally, boolean true on 
the help
+        *                wiki
+        */
+       public static function determineDatabase() {
+               global $wgLanguageCode, $wgSharedHelpLanguages;
+
+               if ( in_array( $wgLanguageCode, $wgSharedHelpLanguages ) && 
$wgLanguageCode !== 'en' ) {
+                       $helpDBname = "{$wgLanguageCode}_wiki";
+               } elseif ( in_array( $wgLanguageCode, array( 'en', 'en-gb', 
'en-ca' ) ) ) {
+                       $helpDBname = 'shoutwiki';
+               } else {
+                       // fall back to English help
+                       $helpDBname = 'shoutwiki';
+               }
+
+               return $helpDBname;
+       }
+
+       /**
+        * Is SharedHelpPages available for the current wiki's language (code)?
+        *
+        * @param string $langCode ISO 639 language code
+        * @return bool True if it's available, otherwise false
+        */
+       public static function isSupportedLanguage() {
+               global $wgLanguageCode, $wgSharedHelpLanguages;
+
+               $isEnglish = in_array( $wgLanguageCode, array( 'en', 'en-gb', 
'en-ca' ) );
+
+               return ( in_array( $wgLanguageCode, $wgSharedHelpLanguages ) || 
$isEnglish );
+       }
 }
diff --git a/extension.json b/extension.json
index f26d600..0cbb678 100644
--- a/extension.json
+++ b/extension.json
@@ -1,6 +1,6 @@
 {
        "name": "SharedHelpPages",
-       "version": "0.3",
+       "version": "0.5",
        "author": [
                "Kunal Mehta",
                "Jack Phoenix"
@@ -9,8 +9,14 @@
        "url": "https://www.mediawiki.org/wiki/Extension:SharedHelpPages";,
        "descriptionmsg": "sharedhelppages-desc",
        "type": "other",
+       "requires": {
+               "MediaWiki": ">= 1.29.0"
+       },
        "config": {
-               "SharedHelpPagesExpiry": 604800,
+               "SharedHelpPagesDevelopmentMode": false,
+               "SharedHelpPagesCacheExpiry": 604800,
+               "SharedHelpPagesAPIUrl": "http://www.shoutwiki.com/w/api.php";,
+               "SharedHelpPagesTimeout": 10,
                "SharedHelpLanguages": [
                        "en",
                        "fi",
@@ -24,28 +30,24 @@
                ]
        },
        "AutoloadClasses": {
-               "SharedHelpPages": "SharedHelpPages.body.php",
-               "SharedHelpPagesHooks": "SharedHelpPages.hooks.php"
+               "SharedHelpPagesHooks": "SharedHelpPages.hooks.php",
+               "SharedHelpPage": "SharedHelpPage.body.php",
+               "SharedHelpPagePage": "SharedHelpPagePage.php",
+               "SharedHelpPageCacheInvalidator": 
"SharedHelpPageCacheInvalidator.php",
+               "SharedHelpPageLocalJobSubmitJob": 
"SharedHelpPageLocalJobSubmitJob.php",
+               "LocalSharedHelpPageCacheUpdateJob": 
"LocalSharedHelpPageCacheUpdateJob.php"
        },
        "Hooks": {
-               "ShowMissingArticle": [
-                       "SharedHelpPagesHooks::onShowMissingArticle"
-               ],
-               "SkinTemplateNavigation::Universal": [
-                       
"SharedHelpPagesHooks::onSkinTemplateNavigationUniversal"
-               ],
-               "LinkBegin": [
-                       "SharedHelpPagesHooks::brokenLink"
-               ],
-               "EditPage::showEditForm:initial": [
-                       "SharedHelpPagesHooks::displayMessageOnEditPage"
-               ],
-               "WantedPages::getQueryInfo": [
-                       "SharedHelpPagesHooks::modifyWantedPagesSQL"
-               ],
-               "SkinTemplateOutputPageBeforeExec": [
-                       
"SharedHelpPagesHooks::onSkinTemplateOutputPageBeforeExec"
-               ]
+               "EditPage::showEditForm:initial": 
"SharedHelpPagesHooks::displayMessageOnEditPage",
+               "SkinTemplateOutputPageBeforeExec": 
"SharedHelpPagesHooks::onSkinTemplateOutputPageBeforeExec",
+               "SkinTemplateNavigation::Universal": 
"SharedHelpPagesHooks::onSkinTemplateNavigationUniversal",
+               "TitleIsAlwaysKnown": 
"SharedHelpPagesHooks::onTitleIsAlwaysKnown",
+               "ArticleFromTitle": "SharedHelpPagesHooks::onArticleFromTitle",
+               "LinksUpdateComplete": 
"SharedHelpPagesHooks::onLinksUpdateComplete",
+               "PageContentInsertComplete": 
"SharedHelpPagesHooks::onPageContentInsertComplete",
+               "ArticleDeleteComplete": 
"SharedHelpPagesHooks::onArticleDeleteComplete",
+               "WikiPageFactory": "SharedHelpPagesHooks::onWikiPageFactory",
+               "WantedPages::getQueryInfo": 
"SharedHelpPagesHooks::modifyWantedPagesSQL"
        },
        "ResourceFileModulePaths": {
                "localBasePath": "",
@@ -57,5 +59,12 @@
                        "position": "top"
                }
        },
+       "JobClasses": {
+               "SharedHelpPageLocalJobSubmitJob": 
"SharedHelpPageLocalJobSubmitJob",
+               "LocalSharedHelpPageCacheUpdateJob": 
"LocalSharedHelpPageCacheUpdateJob"
+       },
+       "ConfigRegistry": {
+               "sharedhelppages": "GlobalVarConfig::newInstance"
+       },
        "manifest_version": 1
 }
diff --git a/i18n/ast.json b/i18n/ast.json
index 6ac361b..c43b713 100644
--- a/i18n/ast.json
+++ b/i18n/ast.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Baxa automáticamente páxines d'ayuda de 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Esta páxina descargóse de 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] y pue editase allí.",
+       "sharedhelppages-notice": "Esta páxina descargóse de 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] y pue editase allí.",
        "sharedhelppages-edit-tab": "Editar en ShoutWiki Hub"
 }
diff --git a/i18n/bn.json b/i18n/bn.json
index 2097c2c..4151735 100644
--- a/i18n/bn.json
+++ b/i18n/bn.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "স্বয়ংক্রিয়ভাবে [http://www.shoutwiki.com/ 
ShoutWiki Hub] থেকে সাহায্য পাতাগুলি নিয়ে আসে।",
-       "sharedhelppages-notice": "এই পাতাটি 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] থেকে ডাউনলোড করা হয়েছে এবং 
সেখানে সম্পাদনা করা যাবে।",
+       "sharedhelppages-notice": "এই পাতাটি [http://www.shoutwiki.com/wiki/$1 
ShoutWiki Hub] থেকে ডাউনলোড করা হয়েছে এবং সেখানে সম্পাদনা করা যাবে।",
        "sharedhelppages-edit-tab": "ShoutWiki Hub সাইটে সম্পাদনা করুন"
 }
diff --git a/i18n/de.json b/i18n/de.json
index 0ce0127..7c10da0 100644
--- a/i18n/de.json
+++ b/i18n/de.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Ermöglicht den automatischen Abruf von 
Hilfeseiten von [http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Diese Seite wurde von 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] heruntergeladen und kann 
dort bearbeitet werden.",
+       "sharedhelppages-notice": "Diese Seite wurde von 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] heruntergeladen und kann dort 
bearbeitet werden.",
        "sharedhelppages-edit-tab": "Auf ShoutWiki Hub bearbeiten"
 }
diff --git a/i18n/en.json b/i18n/en.json
index 02b3d8b..2fd6cfd 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Automatically fetches help pages from 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "This page was downloaded from 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] and can be edited there.",
+       "sharedhelppages-notice": "This page was downloaded from 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] and can be edited there.",
        "sharedhelppages-edit-tab": "Edit on ShoutWiki Hub"
 }
diff --git a/i18n/fi.json b/i18n/fi.json
index 2a88c96..bac8506 100644
--- a/i18n/fi.json
+++ b/i18n/fi.json
@@ -1,10 +1,10 @@
 {
        "@metadata": {
                "authors": [
-                       "Jack Phoenix <[email protected]>"
+                       "Jack Phoenix"
                ]
        },
-       "sharedhelppages-desc": "Automaattisesti hakee ohjesivut 
[http://www.shoutwiki.com/ ShoutWikin englanninkielisestä keskuswikistä]",
-       "sharedhelppages-notice": "Tämä sivu ladattiin 
[http://www.shoutwiki.com/?oldid=$1 ShoutWikin englanninkielisestä 
keskuswikistä] ja sitä voi muokata siellä.",
-       "sharedhelppages-edit-tab": "Muokkaa ShoutWiki Hubissa"
+       "sharedhelppages-desc": "Automaattisesti hakee ohjesivut 
[http://fi.shoutwiki.com/ ShoutWikin keskuswikistä]",
+       "sharedhelppages-notice": "Tämä sivu ladattiin 
[http://fi.shoutwiki.com/wiki/$1 ShoutWikin keskuswikistä] ja sitä voi muokata 
siellä.",
+       "sharedhelppages-edit-tab": "Muokkaa ShoutWikin keskuswikissä"
 }
diff --git a/i18n/fr.json b/i18n/fr.json
index e7bd8c9..f0a91ce 100644
--- a/i18n/fr.json
+++ b/i18n/fr.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Extrait automatiquement les pages d’aide de 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "La page a été téléchargée depuis 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] et peut être modifiée ici.",
+       "sharedhelppages-notice": "La page a été téléchargée depuis 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] et peut être modifiée ici.",
        "sharedhelppages-edit-tab": "Modifier sur ShoutWiki Hub"
 }
diff --git a/i18n/gl.json b/i18n/gl.json
index c51372b..f1e68c7 100644
--- a/i18n/gl.json
+++ b/i18n/gl.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Busca automaticamente páxinas de axuda de 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Esta páxina descargouse de 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] e pode editarse alí.",
+       "sharedhelppages-notice": "Esta páxina descargouse de 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] e pode editarse alí.",
        "sharedhelppages-edit-tab": "Editar en ShoutWiki Hub"
 }
diff --git a/i18n/hsb.json b/i18n/hsb.json
index bcf72d2..a0e17cf 100644
--- a/i18n/hsb.json
+++ b/i18n/hsb.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Wotwołuje strony pomocy z  
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Tuta strona je so z 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] sćahnyła a da so tu 
wobdźěłać.",
+       "sharedhelppages-notice": "Tuta strona je so z 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] sćahnyła a da so tu 
wobdźěłać.",
        "sharedhelppages-edit-tab": "Na ShoutWiki Hub wobdźěłać"
 }
diff --git a/i18n/ie.json b/i18n/ie.json
index a1802a6..52fd903 100644
--- a/i18n/ie.json
+++ b/i18n/ie.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Automaticmen prender auxiliari págines de 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Ti-ci págine ha esset prendet de 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] e es redactibil ta.",
+       "sharedhelppages-notice": "Ti-ci págine ha esset prendet de 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] e es redactibil ta.",
        "sharedhelppages-edit-tab": "Redacter che ShoutWiki Hub"
 }
diff --git a/i18n/it.json b/i18n/it.json
index 2739bf5..6c3c04a 100644
--- a/i18n/it.json
+++ b/i18n/it.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Scarica automaticamente le pagine di aiuto da 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Questa pagina è stata scaricata da 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] e può essere modificata là.",
+       "sharedhelppages-notice": "Questa pagina è stata scaricata da 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] e può essere modificata là.",
        "sharedhelppages-edit-tab": "Modifica su ShoutWiki Hub"
 }
diff --git a/i18n/ja.json b/i18n/ja.json
index 9b3076c..dfa60e0 100644
--- a/i18n/ja.json
+++ b/i18n/ja.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "ヘルプ ページを [http://www.shoutwiki.com/ ShoutWiki 
Hub] から自動的に取得する",
-       "sharedhelppages-notice": "このページは [http://www.shoutwiki.com/?oldid=$1 
ShoutWiki Hub] からダウンロードされたため、ShoutWiki Hub で編集できます。",
+       "sharedhelppages-notice": "このページは [http://www.shoutwiki.com/wiki/$1 
ShoutWiki Hub] からダウンロードされたため、ShoutWiki Hub で編集できます。",
        "sharedhelppages-edit-tab": "ShoutWiki Hub 上で編集"
 }
diff --git a/i18n/ko.json b/i18n/ko.json
index c21535c..6e0acf7 100644
--- a/i18n/ko.json
+++ b/i18n/ko.json
@@ -4,6 +4,6 @@
                        "Hym411"
                ]
        },
-       "sharedhelppages-desc": "[http://www.shoutwiki.com/ 미디어위키.org] 에서 자동으로 
도움말을 불러옵니다",
+       "sharedhelppages-desc": "[http://www.shoutwiki.com/ ShoutWiki Hub] 에서 
자동으로 도움말을 불러옵니다",
        "sharedhelppages-edit-tab": "ShoutWiki Hub에서의 편집"
 }
diff --git a/i18n/lb.json b/i18n/lb.json
index 0781591..3b45762 100644
--- a/i18n/lb.json
+++ b/i18n/lb.json
@@ -6,6 +6,6 @@
                ]
        },
        "sharedhelppages-desc": "Luet automatesch Hëllefssäite vun 
[http://www.shoutwiki.com/ ShoutWiki Hub] erof",
-       "sharedhelppages-notice": "Dës Säit gouf vu 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] erofgelueden a kann do 
geännert ginn.",
+       "sharedhelppages-notice": "Dës Säit gouf vu 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] erofgelueden a kann do 
geännert ginn.",
        "sharedhelppages-edit-tab": "Änneren op ShoutWiki Hub"
 }
diff --git a/i18n/mk.json b/i18n/mk.json
index 0cc06ec..83ff3cc 100644
--- a/i18n/mk.json
+++ b/i18n/mk.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Автоматски презема страници за помош од 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Страницава е преземена од 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] и може тука да се уредува.",
+       "sharedhelppages-notice": "Страницава е преземена од 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] и може тука да се уредува.",
        "sharedhelppages-edit-tab": "Уреди на ShoutWiki Hub"
 }
diff --git a/i18n/nl.json b/i18n/nl.json
index 8354852..4eec672 100644
--- a/i18n/nl.json
+++ b/i18n/nl.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Haalt automatisch hulppagina's op van 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Deze pagina is gedownload van 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] en kan daar bewerkt worden.",
+       "sharedhelppages-notice": "Deze pagina is gedownload van 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] en kan daar bewerkt worden.",
        "sharedhelppages-edit-tab": "Bewerken op ShoutWiki Hub"
 }
diff --git a/i18n/pt-br.json b/i18n/pt-br.json
index dd70086..1523373 100644
--- a/i18n/pt-br.json
+++ b/i18n/pt-br.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Busca automaticamente páginas de ajuda de 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Esta página foi obtida do endereço 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] e pode ser editada lá.",
+       "sharedhelppages-notice": "Esta página foi obtida do endereço 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] e pode ser editada lá.",
        "sharedhelppages-edit-tab": "Editar em ShoutWiki Hub"
 }
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 2a2afa3..dca0dd9 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -5,7 +5,7 @@
                        "Shirayuki"
                ]
        },
-       "sharedhelppages-desc": 
"{{desc|name=SharedHelpPages|url=http://www.shoutwiki.com/wiki/Extension:SharedHelpPages}}";,
-       "sharedhelppages-notice": "Message shown above help pages from 
ShoutWiki Hub. Parameters:\n* $1 - the revision id of the page that was 
fetched",
+       "sharedhelppages-desc": 
"{{desc|name=SharedHelpPages|url=http://www.mediawiki.org/wiki/Extension:SharedHelpPages}}";,
+       "sharedhelppages-notice": "Message shown above help pages from 
ShoutWiki Hub. Parameters:\n* $1 - the name of the help page that was fetched",
        "sharedhelppages-edit-tab": "Text on tab that replaces \"create\", and 
links to the edit interface on ShoutWiki Hub"
 }
diff --git a/i18n/ru.json b/i18n/ru.json
index 7188f74..b63c4e7 100644
--- a/i18n/ru.json
+++ b/i18n/ru.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Автоматически извлекает страницы справки с 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Эта страница была загружена с 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] и может быть теперь 
отредактирована.",
+       "sharedhelppages-notice": "Эта страница была загружена с 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] и может быть теперь 
отредактирована.",
        "sharedhelppages-edit-tab": "Редактировать на ShoutWiki Hub"
 }
diff --git a/i18n/uk.json b/i18n/uk.json
index 8d2c557..10bca8e 100644
--- a/i18n/uk.json
+++ b/i18n/uk.json
@@ -5,6 +5,6 @@
                ]
        },
        "sharedhelppages-desc": "Автоматично витягує сторінки довідки з 
[http://www.shoutwiki.com/ ShoutWiki Hub]",
-       "sharedhelppages-notice": "Ця сторінка була завантажена з 
[http://www.shoutwiki.com/?oldid=$1 ShoutWiki Hub] і може бути відредагована.",
+       "sharedhelppages-notice": "Ця сторінка була завантажена з 
[http://www.shoutwiki.com/wiki/$1 ShoutWiki Hub] і може бути відредагована.",
        "sharedhelppages-edit-tab": "Редагувати на ShoutWiki Hub"
 }
diff --git a/i18n/zh-hans.json b/i18n/zh-hans.json
index 76992e7..94cc198 100644
--- a/i18n/zh-hans.json
+++ b/i18n/zh-hans.json
@@ -6,6 +6,6 @@
                ]
        },
        "sharedhelppages-desc": "自动从[http://www.shoutwiki.com/ ShoutWiki 
Hub]读取帮助页面",
-       "sharedhelppages-notice": "本页面从[http://www.shoutwiki.com/?oldid=$1 
ShoutWiki Hub]下载并可以在此编辑。",
+       "sharedhelppages-notice": "本页面从[http://www.shoutwiki.com/wiki/$1 
ShoutWiki Hub]下载并可以在此编辑。",
        "sharedhelppages-edit-tab": "在ShoutWiki Hub上编辑"
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/366469
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I4f964f3b684d9d8c5812458017f05b941f80e3af
Gerrit-PatchSet: 4
Gerrit-Project: mediawiki/extensions/SharedHelpPages
Gerrit-Branch: master
Gerrit-Owner: Jack Phoenix <[email protected]>
Gerrit-Reviewer: Jack Phoenix <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Siebrand <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to