Aude has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/269396

Change subject: New deployment build: wmf/1.27.0-wmf.13
......................................................................

New deployment build: wmf/1.27.0-wmf.13

adds ArticlePlaceholder, which we want to enable on
the test wikis.

Change-Id: Ia6cc31c92f6d044c9cccfaf9ec3a3f9805bf2e2e
---
M composer.json
M composer.lock
A extensions/ArticlePlaceholder/.gitignore
A extensions/ArticlePlaceholder/.gitreview
A extensions/ArticlePlaceholder/.jscsrc
A extensions/ArticlePlaceholder/.jshintignore
A extensions/ArticlePlaceholder/.jshintrc
A extensions/ArticlePlaceholder/ArticlePlaceholder.alias.php
A extensions/ArticlePlaceholder/ArticlePlaceholder.php
A extensions/ArticlePlaceholder/Gruntfile.js
A extensions/ArticlePlaceholder/Specials/SpecialAboutTopic.php
A extensions/ArticlePlaceholder/composer.json
A extensions/ArticlePlaceholder/i18n/ast.json
A extensions/ArticlePlaceholder/i18n/cs.json
A extensions/ArticlePlaceholder/i18n/de.json
A extensions/ArticlePlaceholder/i18n/en.json
A extensions/ArticlePlaceholder/i18n/eo.json
A extensions/ArticlePlaceholder/i18n/es.json
A extensions/ArticlePlaceholder/i18n/eu.json
A extensions/ArticlePlaceholder/i18n/fr.json
A extensions/ArticlePlaceholder/i18n/gl.json
A extensions/ArticlePlaceholder/i18n/it.json
A extensions/ArticlePlaceholder/i18n/ja.json
A extensions/ArticlePlaceholder/i18n/jv.json
A extensions/ArticlePlaceholder/i18n/ko.json
A extensions/ArticlePlaceholder/i18n/ksh.json
A extensions/ArticlePlaceholder/i18n/ku-latn.json
A extensions/ArticlePlaceholder/i18n/lb.json
A extensions/ArticlePlaceholder/i18n/lt.json
A extensions/ArticlePlaceholder/i18n/mk.json
A extensions/ArticlePlaceholder/i18n/mr.json
A extensions/ArticlePlaceholder/i18n/ms.json
A extensions/ArticlePlaceholder/i18n/oc.json
A extensions/ArticlePlaceholder/i18n/om.json
A extensions/ArticlePlaceholder/i18n/pl.json
A extensions/ArticlePlaceholder/i18n/ps.json
A extensions/ArticlePlaceholder/i18n/qqq.json
A extensions/ArticlePlaceholder/i18n/ru.json
A extensions/ArticlePlaceholder/i18n/sd.json
A extensions/ArticlePlaceholder/i18n/sr-ec.json
A extensions/ArticlePlaceholder/i18n/sr-el.json
A extensions/ArticlePlaceholder/i18n/su.json
A extensions/ArticlePlaceholder/i18n/sv.json
A extensions/ArticlePlaceholder/i18n/tr.json
A extensions/ArticlePlaceholder/i18n/tt-cyrl.json
A extensions/ArticlePlaceholder/i18n/yi.json
A extensions/ArticlePlaceholder/i18n/zh-hans.json
A extensions/ArticlePlaceholder/i18n/zh-hant.json
A extensions/ArticlePlaceholder/includes/Hooks.php
A extensions/ArticlePlaceholder/includes/Lua/Identifier.lua
A 
extensions/ArticlePlaceholder/includes/Lua/Scribunto_LuaArticlePlaceholderLibrary.php
A 
extensions/ArticlePlaceholder/includes/Lua/mw.ext.articlePlaceholder.entityRenderer.lua
A extensions/ArticlePlaceholder/includes/SearchHookHandler.php
A extensions/ArticlePlaceholder/includes/Template/aboutTopic-template-module.xml
A extensions/ArticlePlaceholder/modules/ext.articleplaceholder.createArticle.js
A 
extensions/ArticlePlaceholder/modules/ext.articleplaceholder.defaultDisplay.css
A 
extensions/ArticlePlaceholder/modules/ext.articleplaceholder.defaultDisplaySmall.css
A extensions/ArticlePlaceholder/package.json
A extensions/ArticlePlaceholder/phpcs.xml
A extensions/ArticlePlaceholder/tests/phpunit/Specials/SpecialAboutTopicTest.php
A extensions/ArticlePlaceholder/tests/phpunit/includes/HooksTest.php
A extensions/ArticlePlaceholder/tests/phpunit/includes/SearchHookHandlerTest.php
M vendor/composer/installed.json
63 files changed, 2,346 insertions(+), 3 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikidata 
refs/changes/96/269396/1

diff --git a/composer.json b/composer.json
index 56225ec..4b6f089 100644
--- a/composer.json
+++ b/composer.json
@@ -30,6 +30,7 @@
     ],
     "require": {
         "php": ">=5.3.0",
+        "mediawiki/article-placeholder": "dev-master",
         "propertysuggester/property-suggester": "~2.4.2",
         "wikibase/wikibase": "dev-wmf/1.27.0-wmf.12",
         "wikibase/wikimedia-badges": "dev-master",
@@ -53,4 +54,4 @@
         "classmap-authoritative": true,
         "preferred-install": "dist"
     }
-}
\ No newline at end of file
+}
diff --git a/composer.lock b/composer.lock
index 2b74ad9..396150c 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,8 @@
         "Read more about it at 
https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file";,
         "This file is @generated automatically"
     ],
-    "hash": "79f06d4a6277edaa1ec67ee83b6f4e0d",
-    "content-hash": "eb15b534279575172797aeb34570b551",
+    "hash": "5c3a1d30068cbc37c03c3fa26784fdbf",
+    "content-hash": "6ef12e3509d6635a2efc6f8578b7dd4b",
     "packages": [
         {
             "name": "composer/installers",
@@ -773,6 +773,38 @@
             "time": "2015-03-17 15:21:21"
         },
         {
+            "name": "mediawiki/article-placeholder",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": 
"https://github.com/wikimedia/mediawiki-extensions-ArticlePlaceholder.git";,
+                "reference": "d3fff7b3144c9ba020380f08018c225e42ce49d7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": 
"https://api.github.com/repos/wikimedia/mediawiki-extensions-ArticlePlaceholder/zipball/d3fff7b3144c9ba020380f08018c225e42ce49d7";,
+                "reference": "d3fff7b3144c9ba020380f08018c225e42ce49d7",
+                "shasum": ""
+            },
+            "require-dev": {
+                "jakub-onderka/php-parallel-lint": "0.9.2",
+                "mediawiki/mediawiki-codesniffer": "0.5.1"
+            },
+            "type": "mediawiki-extension",
+            "notification-url": "https://packagist.org/downloads/";,
+            "license": [
+                "GPL-2.0+"
+            ],
+            "authors": [
+                {
+                    "name": "Lucie-Aimée Kaffee"
+                }
+            ],
+            "description": "Provides a special page with Wikibase information 
about a certain topic, with invitation to create an article for the topic",
+            "homepage": 
"https://www.mediawiki.org/wiki/Extension:ArticlePlaceholder";,
+            "time": "2016-02-08 12:46:34"
+        },
+        {
             "name": "propertysuggester/property-suggester",
             "version": "2.4.5",
             "source": {
@@ -1528,6 +1560,7 @@
     "aliases": [],
     "minimum-stability": "stable",
     "stability-flags": {
+        "mediawiki/article-placeholder": 20,
         "wikibase/wikibase": 20,
         "wikibase/wikimedia-badges": 20,
         "wikibase/wikidata.org": 20,
diff --git a/extensions/ArticlePlaceholder/.gitignore 
b/extensions/ArticlePlaceholder/.gitignore
new file mode 100644
index 0000000..f8cf2c3
--- /dev/null
+++ b/extensions/ArticlePlaceholder/.gitignore
@@ -0,0 +1,3 @@
+node_modules/
+npm-debug.log
+
diff --git a/extensions/ArticlePlaceholder/.gitreview 
b/extensions/ArticlePlaceholder/.gitreview
new file mode 100644
index 0000000..4fe5c65
--- /dev/null
+++ b/extensions/ArticlePlaceholder/.gitreview
@@ -0,0 +1,6 @@
+[gerrit]
+host=gerrit.wikimedia.org
+port=29418
+project=mediawiki/extensions/ArticlePlaceholder.git
+defaultbranch=master
+defaultrebase=0
diff --git a/extensions/ArticlePlaceholder/.jscsrc 
b/extensions/ArticlePlaceholder/.jscsrc
new file mode 100644
index 0000000..8bb503d
--- /dev/null
+++ b/extensions/ArticlePlaceholder/.jscsrc
@@ -0,0 +1,12 @@
+{
+       "preset": "wikimedia",
+       "jsDoc": {
+               "checkAnnotations": {
+                       "preset": "jsduck5",
+                       "extra": {
+                               "license": true,
+                               "licence": true
+                       }
+               }
+       }
+}
diff --git a/extensions/ArticlePlaceholder/.jshintignore 
b/extensions/ArticlePlaceholder/.jshintignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/extensions/ArticlePlaceholder/.jshintignore
@@ -0,0 +1 @@
+node_modules
diff --git a/extensions/ArticlePlaceholder/.jshintrc 
b/extensions/ArticlePlaceholder/.jshintrc
new file mode 100644
index 0000000..d123347
--- /dev/null
+++ b/extensions/ArticlePlaceholder/.jshintrc
@@ -0,0 +1,22 @@
+{
+       // Enforcing
+       "bitwise": true,
+       "eqeqeq": true,
+       "latedef": true,
+       "noarg": true,
+       "nonew": true,
+       "undef": true,
+       "unused": true,
+       "strict": false,
+
+       // Environment
+       "browser": true,
+
+       "globals": {
+               "mw": false,
+               "$": false,
+               "jQuery": false,
+               "mediaWiki": false,
+               "OO": false
+       }
+}
diff --git a/extensions/ArticlePlaceholder/ArticlePlaceholder.alias.php 
b/extensions/ArticlePlaceholder/ArticlePlaceholder.alias.php
new file mode 100644
index 0000000..42e7a35
--- /dev/null
+++ b/extensions/ArticlePlaceholder/ArticlePlaceholder.alias.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Aliases for special pages for extension ArticlePlaceholder
+ *
+ * @file
+ * @ingroup Extensions
+ */
+// @codingStandardsIgnoreFile
+
+$specialPageAliases = array();
+
+/** English (English) */
+$specialPageAliases['en'] = array(
+       'AboutTopic' => array( 'AboutTopic', 'FancyUnicorn' ),
+);
diff --git a/extensions/ArticlePlaceholder/ArticlePlaceholder.php 
b/extensions/ArticlePlaceholder/ArticlePlaceholder.php
new file mode 100644
index 0000000..14d27cd
--- /dev/null
+++ b/extensions/ArticlePlaceholder/ArticlePlaceholder.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * AticlePlaceholder extension
+ *
+ * @ingroup Extensions
+ *
+ * @author Lucie-Aimée Kaffee
+ *
+ * The license governing the extension code:
+ * @license GNU General Public Licence 2.0 or later
+ */
+$wgExtensionCredits['other'][] = array(
+       'path' => __FILE__,
+       'name' => 'ArticlePlaceholder',
+       'author' => array(
+               'Lucie-Aimée Kaffee',
+       ),
+       'url' => 'https://www.mediawiki.org/wiki/Extension:ArticlePlaceholder',
+       'descriptionmsg' => 'articleplaceholder-desc',
+);
+
+$wgArticlePlaceholderImageProperty = 'P18';
+
+$wgAutoloadClasses['ArticlePlaceholder\Specials\SpecialAboutTopic']
+       = __DIR__ . '/Specials/SpecialAboutTopic.php';
+$wgAutoloadClasses['ArticlePlaceholder\Lua\Scribunto_LuaArticlePlaceholderLibrary']
+       = __DIR__ . '/includes/Lua/Scribunto_LuaArticlePlaceholderLibrary.php';
+$wgAutoloadClasses['ArticlePlaceholder\Hooks'] = __DIR__ . 
'/includes/Hooks.php';
+$wgAutoloadClasses['ArticlePlaceholder\SearchHookHandler']
+       = __DIR__ . '/includes/SearchHookHandler.php';
+
+$wgHooks['ScribuntoExternalLibraries'][]
+       = '\ArticlePlaceholder\Hooks::onScribuntoExternalLibraries';
+$wgHooks['ScribuntoExternalLibraryPaths'][]
+       = '\ArticlePlaceholder\Hooks::registerScribuntoExternalLibraryPaths';
+$wgHooks['SpecialSearchResultsAppend'][]
+       = '\ArticlePlaceholder\SearchHookHandler::onSpecialSearchResultsAppend';
+
+$wgHooks['UnitTestsList'][] = 'ArticlePlaceholder\Hooks::onUnitTestsList';
+
+$wgMessagesDirs['ArticlePlaceholder'] = __DIR__ . '/i18n';
+$wgExtensionMessagesFiles['ArticlePlaceholderAliases'] = __DIR__ . 
'/ArticlePlaceholder.alias.php';
+
+$wgSpecialPages['AboutTopic'] = array(
+       'ArticlePlaceholder\Specials\SpecialAboutTopic',
+       'newFromGlobalState'
+);
+
+preg_match( '+' . preg_quote( DIRECTORY_SEPARATOR ) . '(?:vendor|extensions)'
+       . preg_quote( DIRECTORY_SEPARATOR ) . '.*+', __DIR__, $remoteExtPath );
+
+$commonModuleInfo = array(
+       'localBasePath' => __DIR__ . '/modules',
+       'remoteExtPath' => '..' . $remoteExtPath[0] . '/modules',
+);
+
+$wgResourceModules['ext.articleplaceholder.createArticle'] = array(
+       'position' => 'bottom',
+       'scripts' => 'ext.articleplaceholder.createArticle.js',
+       'dependencies' => array(
+               'oojs-ui',
+               'mediawiki.api',
+               'mediawiki.Title',
+               'mediawiki.util'
+       ),
+       'messages' => array(
+               'articleplaceholder-abouttopic-create-article',
+               'articleplaceholder-abouttopic-article-exists-error',
+               'articleplaceholder-abouttopic-create-article-submit-button'
+       ),
+) + $commonModuleInfo;
+
+$wgResourceModules['ext.articleplaceholder.defaultDisplay'] = array(
+       'styles' => array(
+               'ext.articleplaceholder.defaultDisplay.css',
+               'ext.articleplaceholder.defaultDisplaySmall.css' => array( 
'media' => '(max-width: 880px)' ),
+       ),
+       'position' => 'top',
+) + $commonModuleInfo;
diff --git a/extensions/ArticlePlaceholder/Gruntfile.js 
b/extensions/ArticlePlaceholder/Gruntfile.js
new file mode 100644
index 0000000..56ff218
--- /dev/null
+++ b/extensions/ArticlePlaceholder/Gruntfile.js
@@ -0,0 +1,35 @@
+/*jshint node:true */
+module.exports = function ( grunt ) {
+       grunt.loadNpmTasks( 'grunt-contrib-jshint' );
+       grunt.loadNpmTasks( 'grunt-jsonlint' );
+       grunt.loadNpmTasks( 'grunt-banana-checker' );
+       grunt.loadNpmTasks( 'grunt-jscs' );
+
+       grunt.initConfig( {
+               jshint: {
+                       options: {
+                               jshintrc: true
+                       },
+                       all: [
+                               '*.js',
+                               'modules/**/*.js'
+                       ]
+               },
+               jscs: {
+                       src: '<%= jshint.all %>'
+               },
+               banana: {
+                       all: 'i18n/'
+               },
+               jsonlint: {
+                       all: [
+                               '*.json',
+                               '**/*.json',
+                               '!node_modules/**'
+                       ]
+               }
+       } );
+
+       grunt.registerTask( 'test', [ 'jshint', 'jscs', 'jsonlint', 'banana' ] 
);
+       grunt.registerTask( 'default', 'test' );
+};
diff --git a/extensions/ArticlePlaceholder/Specials/SpecialAboutTopic.php 
b/extensions/ArticlePlaceholder/Specials/SpecialAboutTopic.php
new file mode 100644
index 0000000..cc93f3e
--- /dev/null
+++ b/extensions/ArticlePlaceholder/Specials/SpecialAboutTopic.php
@@ -0,0 +1,343 @@
+<?php
+
+namespace ArticlePlaceholder\Specials;
+
+use Html;
+use OOUI;
+use SiteStore;
+use SpecialPage;
+use Title;
+use Wikibase\Client\Store\TitleFactory;
+use Wikibase\Client\WikibaseClient;
+use Wikibase\DataModel\Entity\EntityIdParser;
+use Wikibase\DataModel\Entity\EntityIdParsingException;
+use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\DataModel\Services\Lookup\EntityLookup;
+use Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookupFactory;
+use Wikibase\Lib\Store\SiteLinkLookup;
+
+/**
+ * The AboutTopic SpecialPage for the ArticlePlaceholder extension
+ *
+ * @ingroup Extensions
+ * @author Lucie-Aimée Kaffee
+ * @license GNU General Public Licence 2.0 or later
+ */
+class SpecialAboutTopic extends SpecialPage {
+
+       public static function newFromGlobalState() {
+               $wikibaseClient = WikibaseClient::getDefaultInstance();
+               return new self(
+                       $wikibaseClient->getEntityIdParser(),
+                       
$wikibaseClient->getLanguageFallbackLabelDescriptionLookupFactory(),
+                       $wikibaseClient->getStore()->getSiteLinkLookup(),
+                       $wikibaseClient->getSiteStore(),
+                       new TitleFactory(),
+                       $wikibaseClient->getSettings()->getSetting( 
'siteGlobalID' ),
+                       $wikibaseClient->getStore()->getEntityLookup()
+               );
+       }
+
+       /**
+        * @var EntityIdParser
+        */
+       private $idParser;
+
+       /**
+        * @var LanguageFallbackLabelDescriptionLookupFactory
+        */
+       private $termLookupFactory;
+
+       /**
+        * @var SitelinkLookup
+        */
+       private $sitelinkLookup;
+
+       /**
+        * @var SiteStore
+        */
+       private $siteStore;
+
+       /**
+        * @var TitleFactory
+        */
+       private $titleFactory;
+
+       /**
+        * @var string
+        */
+       private $siteGlobalID;
+
+       /**
+        * @var EntityLookup
+        */
+       private $entityLookup;
+
+       /**
+        * Initialize the special page.
+        */
+       public function __construct(
+               EntityIdParser $idParser,
+               LanguageFallbackLabelDescriptionLookupFactory 
$termLookupFactory,
+               SiteLinkLookup $sitelinkLookup,
+               SiteStore $siteStore,
+               TitleFactory $titleFactory,
+               $siteGlobalID,
+               EntityLookup $entityLookup
+       ) {
+               $this->idParser = $idParser;
+               $this->termLookupFactory = $termLookupFactory;
+               $this->sitelinkLookup = $sitelinkLookup;
+               $this->siteStore = $siteStore;
+               $this->titleFactory = $titleFactory;
+               $this->siteGlobalID = $siteGlobalID;
+               $this->entityLookup = $entityLookup;
+
+               parent::__construct( 'AboutTopic' );
+       }
+
+       /**
+        * @param string|null $sub
+        */
+       public function execute( $sub ) {
+               $this->setHeaders();
+               $this->showContent( $sub );
+       }
+
+       /**
+        * @param string|null $entityIdString
+        */
+       private function showContent( $entityIdString ) {
+               $entityId = $this->getItemIdParam( 'entityid', $entityIdString 
);
+
+               if ( $entityId === null ) {
+                       $this->createForm();
+                       return;
+               }
+               if ( !$this->entityLookup->hasEntity( $entityId ) ) {
+                       $this->createForm();
+                       $message = $this->msg( 
'articleplaceholder-abouttopic-no-entity-error' );
+                       $this->getOutput()->addWikiText( $message->text() );
+                       return;
+               }
+
+               $articleOnWiki = $this->getArticleOnWiki( $entityId );
+
+               if ( $articleOnWiki !== null ) {
+                       $this->getOutput()->redirect( $articleOnWiki );
+               } else {
+                       $this->showPlaceholder( $entityId );
+               }
+       }
+
+       /**
+        * @see SpecialPage::getDescription
+        *
+        * @return string
+        */
+       public function getDescription() {
+               return $this->msg( 'articleplaceholder-abouttopic' )->text();
+       }
+
+       protected function getGroupName() {
+               return 'other';
+       }
+
+       /**
+        * Create html elements
+        */
+       protected function createForm() {
+               // Form header
+               $this->getOutput()->addHTML(
+                       Html::openElement(
+                               'form',
+                               array(
+                                       'method' => 'get',
+                                       'action' => 
$this->getPageTitle()->getFullUrl(),
+                                       'name' => 'ap-abouttopic',
+                                       'id' => 'ap-abouttopic-form1',
+                                       'class' => 'ap-form'
+                               )
+                       )
+               );
+
+               // Form elements
+               $this->getOutput()->addHTML( $this->getFormElements() );
+
+               // Form body
+               $this->getOutput()->addHTML(
+                       Html::input(
+                               'submit',
+                               $this->msg( 
'articleplaceholder-abouttopic-submit' )->text(),
+                               'submit',
+                               array( 'id' => 'submit' )
+                       )
+                       . Html::closeElement( 'fieldset' )
+                       . Html::closeElement( 'form' )
+               );
+       }
+
+       /**
+        * Returns the form elements.
+        *
+        * @return string
+        * @todo exchange all those . Html::element( 'br' ) with something 
pretty
+        */
+       protected function getFormElements() {
+               return Html::rawElement(
+                       'p',
+                       array(),
+                       $this->msg( 'articleplaceholder-abouttopic-intro' 
)->parse()
+               )
+               . Html::element( 'br' )
+               . Html::element(
+                       'label',
+                       array(
+                               'for' => 'ap-abouttopic-entityid',
+                               'class' => 'ap-label'
+                       ),
+                       $this->msg( 'articleplaceholder-abouttopic-entityid' 
)->text()
+               )
+               . Html::element( 'br' )
+               . Html::input(
+                       'entityid',
+                       $this->getRequest()->getVal( 'entityid' ),
+                       'text', array(
+                               'class' => 'ap-input',
+                               'id' => 'ap-abouttopic-entityid'
+                       )
+               )
+               . Html::element( 'br' );
+       }
+
+       private function getTextParam( $name, $fallback ) {
+               $value = $this->getRequest()->getText( $name, $fallback );
+               return trim( $value );
+       }
+
+       /**
+        * @param string $name
+        * @param string $fallback
+        *
+        * @return ItemId|null
+        * @throws @todo UserInputException
+        */
+       private function getItemIdParam( $name, $fallback ) {
+               $rawId = $this->getTextParam( $name, $fallback );
+
+               if ( $rawId === '' ) {
+                       return null;
+               }
+
+               try {
+                       $id = $this->idParser->parse( $rawId );
+                       if ( !( $id instanceof ItemId ) ) {
+                               throw new EntityIdParsingException();
+                       }
+
+                       return $id;
+               } catch ( EntityIdParsingException $ex ) {
+                       // @todo proper Exception Handling
+                       $this->getOutput()->addWikiText( $ex->getMessage() );
+               }
+
+               return null;
+       }
+
+       /**
+        * Show placeholder and include template to call lua module
+        * @param ItemId $entityId
+        */
+       private function showPlaceholder( ItemId $entityId ) {
+               $this->getOutput()->addWikiText( '{{aboutTopic|' . 
$entityId->getSerialization() . '}}' );
+               $label = $this->getLabel( $entityId );
+               $this->showTitle( $label );
+               $this->showCreateArticle( $label );
+               $this->showLanguageLinks( $entityId );
+       }
+
+       private function showCreateArticle( $label ) {
+               $output = $this->getOutput();
+
+               $output->enableOOUI();
+               $modules = array(
+                       'ext.articleplaceholder.createArticle',
+                       'ext.articleplaceholder.defaultDisplay'
+               );
+               $output->addModules( $modules );
+               $output->addJsConfigVars( 'apLabel', $label );
+
+               $button = new OOUI\ButtonWidget( array(
+                       'id' => 'create-article-button',
+                       'infusable' => true,
+                       'label' => $this->msg( 
'articleplaceholder-abouttopic-create-article-button' )->text(),
+                       'target' => 'blank'
+               ) );
+
+               $output->addHTML( $button );
+       }
+
+       /**
+        * @param ItemId $entityId
+        * @return string|null label
+        */
+       private function getLabel( ItemId $entityId ) {
+               $label = $this->termLookupFactory->newLabelDescriptionLookup( 
$this->getLanguage() )
+                       ->getLabel( $entityId );
+
+               if ( $label !== null ) {
+                       return $label->getText();
+               }
+
+               return null;
+       }
+
+       /**
+        * Show label as page title
+        * @param string|null $label
+        */
+       private function showTitle( $label ) {
+               if ( $label !== null ) {
+                       $this->getOutput()->setPageTitle( htmlspecialchars( 
$label ) );
+               }
+       }
+
+       /**
+        * Set language links
+        * @param ItemId $entityId
+        * @todo set links to other projects in sidebar, too!
+        */
+       private function showLanguageLinks( ItemId $entityId ) {
+               $siteLinks = $this->sitelinkLookup->getSiteLinksForItem( 
$entityId );
+               $languageLinks = array();
+
+               foreach ( $siteLinks as $siteLink ) {
+                       $languageCode = $this->siteStore->getSite( 
$siteLink->getSiteId() )->getLanguageCode();
+
+                       if ( $languageCode !== null ) {
+                               $languageLinks[$languageCode] = $languageCode . 
':' . $siteLink->getPageName();
+                       }
+               }
+
+               $this->getOutput()->setLanguageLinks( $languageLinks );
+       }
+
+       /**
+        * @param ItemId $entityId
+        * @return Title
+        */
+       private function getArticleOnWiki( ItemId $entityId ) {
+               $sitelinkTitles = $this->sitelinkLookup->getLinks(
+                       array( $entityId->getNumericId() ),
+                       array( $this->siteGlobalID )
+               );
+
+               if ( isset( $sitelinkTitles[0][1] ) ) {
+                       $sitelinkTitle = $sitelinkTitles[0][1];
+                       return $this->titleFactory->newFromText( $sitelinkTitle 
)->getLinkURL();
+               }
+
+               return null;
+       }
+
+}
diff --git a/extensions/ArticlePlaceholder/composer.json 
b/extensions/ArticlePlaceholder/composer.json
new file mode 100644
index 0000000..b939a11
--- /dev/null
+++ b/extensions/ArticlePlaceholder/composer.json
@@ -0,0 +1,26 @@
+{
+       "name": "mediawiki/article-placeholder",
+       "type": "mediawiki-extension",
+       "description": "Provides a special page with Wikibase information about 
a certain topic, with invitation to create an article for the topic",
+       "homepage": 
"https://www.mediawiki.org/wiki/Extension:ArticlePlaceholder";,
+       "license": "GPL-2.0+",
+       "authors": [
+               {
+                       "name": "Lucie-Aimée Kaffee"
+               }
+       ],
+       "support": {
+               "issues": "https://phabricator.wikimedia.org/";,
+               "irc": "irc://irc.freenode.net/wikidata"
+       },
+       "require-dev": {
+               "jakub-onderka/php-parallel-lint": "0.9.2",
+               "mediawiki/mediawiki-codesniffer": "0.5.1"
+       },
+       "scripts": {
+               "test": [
+                       "parallel-lint . --exclude vendor",
+                       "phpcs -p -s"
+               ]
+       }
+}
diff --git a/extensions/ArticlePlaceholder/i18n/ast.json 
b/extensions/ArticlePlaceholder/i18n/ast.json
new file mode 100644
index 0000000..e206832
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/ast.json
@@ -0,0 +1,22 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Xuacu"
+               ]
+       },
+       "articleplaceholder-desc": "Ufre una páxina especial con información de 
{{WBREPONAME}} sobro un tema determináu, con invitación a crear un artículu pal 
tema",
+       "articleplaceholder-abouttopic": "Tocante al asuntu",
+       "articleplaceholder-abouttopic-intro": "Esta páxina especial xenera una 
páxina de conteníu sobro un asuntu determináu con información de 
{{WBREPONAME}}",
+       "articleplaceholder-abouttopic-entityid": "Escribe una ID d'entidá pa 
recibir una maqueta d'artículu xenerada automáticamente.",
+       "articleplaceholder-abouttopic-submit": "crear",
+       "articleplaceholder-abouttopic-no-entity-error": "Esta nun ye una id 
d'entidá válida.",
+       "articleplaceholder-abouttopic-create-article": "Crear un artículu 
nuevu col títulu",
+       "articleplaceholder-abouttopic-create-article-button": "Crear un 
artículu",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Unviar",
+       "articleplaceholder-abouttopic-article-exists-error": "Yá esiste un 
artículu con esi nome.",
+       "articleplaceholder-abouttopic-lua-entity": "Entidá",
+       "articleplaceholder-abouttopic-lua-reference": "Referencia",
+       "articleplaceholder-abouttopic-lua-qualifier": "Cualificador",
+       "articleplaceholder-abouttopic-lua-identifier": "Identificador",
+       "articleplaceholder-search-header": "Descubrir datos del tema"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/cs.json 
b/extensions/ArticlePlaceholder/i18n/cs.json
new file mode 100644
index 0000000..3744e4d
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/cs.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Cvanca"
+               ]
+       },
+       "articleplaceholder-abouttopic": "O Tématu"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/de.json 
b/extensions/ArticlePlaceholder/i18n/de.json
new file mode 100644
index 0000000..0f64b2b
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/de.json
@@ -0,0 +1,23 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Metalhead64"
+               ]
+       },
+       "articleplaceholder-desc": "Ergänzt eine Spezialseite mit 
{{WBREPONAME}}-Informationen über ein bestimmtes Thema mit einer Einladung zum 
Erstellen eines Artikels zum Thema",
+       "articleplaceholder-abouttopic": "Über Thema",
+       "articleplaceholder-abouttopic-intro": "Diese Spezialseite erzeugt eine 
Inhaltsseite über ein bestimmtes Thema mit Informationen aus {{WBREPONAME}}",
+       "articleplaceholder-abouttopic-entityid": "Gib die Objektkennung ein, 
um einen automatisch erzeugten Artikelplatzhalter zu erhalten.",
+       "articleplaceholder-abouttopic-submit": "entwerfen",
+       "articleplaceholder-abouttopic-no-entity-error": "Dies ist keine 
gültige Objektkennung.",
+       "articleplaceholder-abouttopic-create-article": "Einen neuen Artikel 
mit dem Titel erstellen",
+       "articleplaceholder-abouttopic-create-article-button": "Einen Artikel 
erstellen",
+       "articleplaceholder-abouttopic-create-article-submit-button": 
"Übermitteln",
+       "articleplaceholder-abouttopic-article-exists-error": "Ein Artikel mit 
diesem Namen ist bereits vorhanden",
+       "articleplaceholder-abouttopic-lua-entity": "Objekt",
+       "articleplaceholder-abouttopic-lua-description": "Beschreibung:",
+       "articleplaceholder-abouttopic-lua-reference": "Referenz",
+       "articleplaceholder-abouttopic-lua-qualifier": "Qualifikator",
+       "articleplaceholder-abouttopic-lua-identifier": "Identifikator",
+       "articleplaceholder-search-header": "Daten zum Thema entdecken"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/en.json 
b/extensions/ArticlePlaceholder/i18n/en.json
new file mode 100644
index 0000000..c612e53
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/en.json
@@ -0,0 +1,22 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Lucie-Aimée Kaffee"
+               ]
+       },
+       "articleplaceholder-desc": "Provides a special page with {{WBREPONAME}} 
information about a certain topic, with invitation to create an article for the 
topic",
+       "articleplaceholder-abouttopic": "About topic",
+       "articleplaceholder-abouttopic-intro": "This special page generates a 
content page about a certain topic with {{WBREPONAME}} information",
+       "articleplaceholder-abouttopic-entityid": "Enter an entity id to get an 
auto-generated article placeholder.",
+       "articleplaceholder-abouttopic-submit": "craft",
+       "articleplaceholder-abouttopic-no-entity-error": "This is not a valid 
entity id.",
+       "articleplaceholder-abouttopic-create-article": "Create a new article 
with the title",
+       "articleplaceholder-abouttopic-create-article-button": "Create an 
article",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Submit",
+       "articleplaceholder-abouttopic-article-exists-error": "An article with 
this name already exists",
+       "articleplaceholder-abouttopic-lua-entity": "Entity",
+       "articleplaceholder-abouttopic-lua-reference": "Reference",
+       "articleplaceholder-abouttopic-lua-qualifier": "Qualifier",
+       "articleplaceholder-abouttopic-lua-identifier": "Identifier",
+       "articleplaceholder-search-header": "Discover data on the topic"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/eo.json 
b/extensions/ArticlePlaceholder/i18n/eo.json
new file mode 100644
index 0000000..e0ac0fa
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/eo.json
@@ -0,0 +1,24 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Robin van der Vliet",
+                       "Venca24",
+                       "KuboF"
+               ]
+       },
+       "articleplaceholder-desc": "Provizas specialan paĝon kun informoj de 
{{WBREPONAME}} pri koncerna temo kun invito krei artikolon pri la temo",
+       "articleplaceholder-abouttopic": "Pri la temo",
+       "articleplaceholder-abouttopic-intro": "Tiu ĉi speciala paĝo generas 
enhavpaĝon pri iu temo kun informoj de {{WBREPONAME}}",
+       "articleplaceholder-abouttopic-entityid": "Tajpu ento-identigilon por 
aŭtomate generitan anstataŭigon de artikolo.",
+       "articleplaceholder-abouttopic-submit": "ek",
+       "articleplaceholder-abouttopic-no-entity-error": "Tio ĉi ne estas ĝusta 
identigilo.",
+       "articleplaceholder-abouttopic-create-article": "Krei novan artikolon 
kun tiu ĉi titolo",
+       "articleplaceholder-abouttopic-create-article-button": "Krei artikolon",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Ek",
+       "articleplaceholder-abouttopic-article-exists-error": "Artikolo kun tiu 
ĉi nomo jam ekzistas",
+       "articleplaceholder-abouttopic-lua-entity": "Ento",
+       "articleplaceholder-abouttopic-lua-reference": "Referenco(j)",
+       "articleplaceholder-abouttopic-lua-qualifier": "Kvalifilo",
+       "articleplaceholder-abouttopic-lua-identifier": "Identigilo",
+       "articleplaceholder-search-header": "Malkovru datumojn pri la temo"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/es.json 
b/extensions/ArticlePlaceholder/i18n/es.json
new file mode 100644
index 0000000..9f15c43
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/es.json
@@ -0,0 +1,23 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Macofe",
+                       "SinNovedades"
+               ]
+       },
+       "articleplaceholder-desc": "Proporciona una página especial información 
de {{WBREPONAME}} acerca de un determinado tema, con invitación a crear un 
artículo para el tema",
+       "articleplaceholder-abouttopic": "Sobre el tema",
+       "articleplaceholder-abouttopic-intro": "Esta página especial genera una 
página de contenido sobre un tema determinado con información de 
{{WBREPONAME}}",
+       "articleplaceholder-abouttopic-entityid": "Escribe un identificador de 
entidad para obtener un posicionador de artículo autogenerado.",
+       "articleplaceholder-abouttopic-submit": "crear",
+       "articleplaceholder-abouttopic-no-entity-error": "Este identificador de 
identidad no es válido.",
+       "articleplaceholder-abouttopic-create-article": "Crear un artículo 
nuevo con el título",
+       "articleplaceholder-abouttopic-create-article-button": "Crear un 
artículo",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Enviar",
+       "articleplaceholder-abouttopic-article-exists-error": "Ya existe un 
arttículo con este nombre",
+       "articleplaceholder-abouttopic-lua-entity": "Entidad",
+       "articleplaceholder-abouttopic-lua-reference": "Referencia",
+       "articleplaceholder-abouttopic-lua-qualifier": "Calificador",
+       "articleplaceholder-abouttopic-lua-identifier": "Identificador",
+       "articleplaceholder-search-header": "Descubrir datos sobre el tema"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/eu.json 
b/extensions/ArticlePlaceholder/i18n/eu.json
new file mode 100644
index 0000000..0f6c914
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/eu.json
@@ -0,0 +1,9 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Subi"
+               ]
+       },
+       "articleplaceholder-abouttopic": "Gaiari buruz",
+       "articleplaceholder-abouttopic-lua-identifier": "Identifikatzailea"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/fr.json 
b/extensions/ArticlePlaceholder/i18n/fr.json
new file mode 100644
index 0000000..3ddbf4a
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/fr.json
@@ -0,0 +1,23 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Gomoko",
+                       "Wladek92"
+               ]
+       },
+       "articleplaceholder-desc": "Fournit une page spéciale avec 
l’information {{WBREPONAME}} sur un certain sujet, avec une invitation à créer 
un article pour le sujet",
+       "articleplaceholder-abouttopic": "Sujet \"À propos\"",
+       "articleplaceholder-abouttopic-intro": "Cette page spéciale génère une 
page de contenu sur un certain sujet avec l’information {{WBREPONAME}}",
+       "articleplaceholder-abouttopic-entityid": "Entrer un id d’entité pour 
obtenir un article fictif généré automatiquement.",
+       "articleplaceholder-abouttopic-submit": "réaliser",
+       "articleplaceholder-abouttopic-no-entity-error": "Ce n’est pas un id 
d’entité valide.",
+       "articleplaceholder-abouttopic-create-article": "Créer un nouvel 
article avec le titre",
+       "articleplaceholder-abouttopic-create-article-button": "Créer un 
article",
+       "articleplaceholder-abouttopic-create-article-submit-button": 
"Soumettre",
+       "articleplaceholder-abouttopic-article-exists-error": "Un article avec 
ce nom existe déjà",
+       "articleplaceholder-abouttopic-lua-entity": "Entité",
+       "articleplaceholder-abouttopic-lua-reference": "Référence",
+       "articleplaceholder-abouttopic-lua-qualifier": "Qualificatif",
+       "articleplaceholder-abouttopic-lua-identifier": "Identifiant",
+       "articleplaceholder-search-header": "Découvrir les données sur le sujet"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/gl.json 
b/extensions/ArticlePlaceholder/i18n/gl.json
new file mode 100644
index 0000000..55ea653
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/gl.json
@@ -0,0 +1,22 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Elisardojm"
+               ]
+       },
+       "articleplaceholder-desc": "Proporciona unha páxina especial con 
información de {{WBREPONAME}} sobre tema determinado, con invitación a crear un 
artigo para o tema",
+       "articleplaceholder-abouttopic": "Sobre o tema",
+       "articleplaceholder-abouttopic-intro": "Esta páxina especial xenera 
unha páxina de contido sobre un tema determinado con información de 
{{WBREPONAME}}",
+       "articleplaceholder-abouttopic-entityid": "Indique un identificador de 
entidade para obter un marcador de artigo autoxenerado.",
+       "articleplaceholder-abouttopic-submit": "crear",
+       "articleplaceholder-abouttopic-no-entity-error": "Este identificador de 
identidade non é válido.",
+       "articleplaceholder-abouttopic-create-article": "Crear un artigo novo 
co título",
+       "articleplaceholder-abouttopic-create-article-button": "Crear un 
artigo",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Enviar",
+       "articleplaceholder-abouttopic-article-exists-error": "Xa existe un 
artigo con ese nome.",
+       "articleplaceholder-abouttopic-lua-entity": "Entidade",
+       "articleplaceholder-abouttopic-lua-reference": "Referencia",
+       "articleplaceholder-abouttopic-lua-qualifier": "Cualificador",
+       "articleplaceholder-abouttopic-lua-identifier": "Identificador",
+       "articleplaceholder-search-header": "Descubrir datos sobre o tema"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/it.json 
b/extensions/ArticlePlaceholder/i18n/it.json
new file mode 100644
index 0000000..8aef5b4
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/it.json
@@ -0,0 +1,23 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Beta16"
+               ]
+       },
+       "articleplaceholder-desc": "Fornisce una pagina speciale con 
informazioni da {{WBREPONAME}} su un certo argomento, con l'invito a creare una 
voce su di esso",
+       "articleplaceholder-abouttopic": "Sull'argomento",
+       "articleplaceholder-abouttopic-intro": "Questa pagina speciale genera 
una pagina di contenuto su un certo argomento con informazioni da 
{{WBREPONAME}}",
+       "articleplaceholder-abouttopic-entityid": "Inserisci un ID entità per 
ottenere una voce segnaposto auto-generata.",
+       "articleplaceholder-abouttopic-submit": "crea",
+       "articleplaceholder-abouttopic-no-entity-error": "Questo non è un ID 
entità valido.",
+       "articleplaceholder-abouttopic-create-article": "Crea una nuova voce 
con il titolo",
+       "articleplaceholder-abouttopic-create-article-button": "Crea una voce",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Invia",
+       "articleplaceholder-abouttopic-article-exists-error": "Una voce con 
questo nome esiste già",
+       "articleplaceholder-abouttopic-lua-entity": "Entità",
+       "articleplaceholder-abouttopic-lua-description": "Descrizione:",
+       "articleplaceholder-abouttopic-lua-reference": "Riferimento",
+       "articleplaceholder-abouttopic-lua-qualifier": "Qualificatore",
+       "articleplaceholder-abouttopic-lua-identifier": "Identificatore",
+       "articleplaceholder-search-header": "Scopri i dati sull'argomento"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/ja.json 
b/extensions/ArticlePlaceholder/i18n/ja.json
new file mode 100644
index 0000000..4685ee6
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/ja.json
@@ -0,0 +1,11 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Sujiniku"
+               ]
+       },
+       "articleplaceholder-abouttopic-no-entity-error": 
"これは有効なエンティティIDではありません。",
+       "articleplaceholder-abouttopic-create-article-button": "記事を作成する",
+       "articleplaceholder-abouttopic-create-article-submit-button": "提出する",
+       "articleplaceholder-abouttopic-lua-description": "説明:"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/jv.json 
b/extensions/ArticlePlaceholder/i18n/jv.json
new file mode 100644
index 0000000..56f923c
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/jv.json
@@ -0,0 +1,16 @@
+{
+       "@metadata": {
+               "authors": [
+                       "NoiX180"
+               ]
+       },
+       "articleplaceholder-desc": "Nyadhiyakaké kaca mirunggan mawa pratélan 
{{WBREPONAME}} bab rembug tinemtu, sarta undangan ngripta artikel jroning 
rembug iku",
+       "articleplaceholder-abouttopic": "Bab Rembug",
+       "articleplaceholder-abouttopic-intro": "Kaca mirunggan iki ngasilaké 
kaca isi bab rembug tinamtu mawa pratélan {{WBREPONAME}}",
+       "articleplaceholder-abouttopic-create-article": "Ngripta artikel anyar 
mawa sesirah iku",
+       "articleplaceholder-abouttopic-create-article-button": "Ngripta 
artikel",
+       "articleplaceholder-abouttopic-create-article-submit-button": 
"Kumpulaké",
+       "articleplaceholder-abouttopic-article-exists-error": "Artikel asesirah 
mangkéné wis ana",
+       "articleplaceholder-abouttopic-lua-reference": "Rujukan",
+       "articleplaceholder-search-header": "Temokaké data bab rembug iku"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/ko.json 
b/extensions/ArticlePlaceholder/i18n/ko.json
new file mode 100644
index 0000000..f8ed0bf
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/ko.json
@@ -0,0 +1,20 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Revi"
+               ]
+       },
+       "articleplaceholder-desc": "특정 주제에 대한 {{WBREPONAME}} 정보를 다루는 특수 문서를 
제공하며, 해당 주제에 대한 새 문서를 만들도록 추천합니다",
+       "articleplaceholder-abouttopic": "주제에 대하여",
+       "articleplaceholder-abouttopic-intro": "이 특수 문서는 {{WBREPONAME}}으로 특정한 
주제에 대한 문서를 생성합니다.",
+       "articleplaceholder-abouttopic-entityid": "개체 ID를 입력하여 자동 생성된 문서를 
얻어오세요.",
+       "articleplaceholder-abouttopic-no-entity-error": "유효한 개체 ID가 아닙니다.",
+       "articleplaceholder-abouttopic-create-article": "이 제목으로 새 문서 만들기",
+       "articleplaceholder-abouttopic-create-article-button": "새 문서 만들기",
+       "articleplaceholder-abouttopic-create-article-submit-button": "제출",
+       "articleplaceholder-abouttopic-article-exists-error": "이 제목으로 된 문서가 이미 
존재합니다",
+       "articleplaceholder-abouttopic-lua-entity": "개체",
+       "articleplaceholder-abouttopic-lua-reference": "참고",
+       "articleplaceholder-abouttopic-lua-qualifier": "한정어",
+       "articleplaceholder-search-header": "주제에 대한 데이터 탐색"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/ksh.json 
b/extensions/ArticlePlaceholder/i18n/ksh.json
new file mode 100644
index 0000000..555d4fa
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/ksh.json
@@ -0,0 +1,15 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Purodha"
+               ]
+       },
+       "articleplaceholder-desc": "Brängk en {{int:specialpage}} med Aanjahbe 
{{WBREPONAME}} övver e Tehma, met dä Bedd, doh drövver en neuje Sigg ze 
schrihve. ",
+       "articleplaceholder-abouttopic-submit": "Lohß Jonn!",
+       "articleplaceholder-abouttopic-create-article": "Donn en Sigg met dä 
Övverschreff aanlähje.",
+       "articleplaceholder-abouttopic-create-article-button": "Donn en Sigg 
met aanlähje.",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Lohß 
jonn!",
+       "articleplaceholder-abouttopic-article-exists-error": "En Sigg met dä 
Övverschreff jidd_et ald.",
+       "articleplaceholder-abouttopic-lua-reference": "Fohßnoht",
+       "articleplaceholder-abouttopic-lua-identifier": "Kännong"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/ku-latn.json 
b/extensions/ArticlePlaceholder/i18n/ku-latn.json
new file mode 100644
index 0000000..0dcf879
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/ku-latn.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "George Animal"
+               ]
+       },
+       "articleplaceholder-abouttopic": "Di derbarê mijarê de"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/lb.json 
b/extensions/ArticlePlaceholder/i18n/lb.json
new file mode 100644
index 0000000..1d62af9
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/lb.json
@@ -0,0 +1,12 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Robby"
+               ]
+       },
+       "articleplaceholder-abouttopic": "Iwwert Thema",
+       "articleplaceholder-abouttopic-create-article-button": "En Artikel 
uleeën",
+       "articleplaceholder-abouttopic-lua-entity": "Objet",
+       "articleplaceholder-abouttopic-lua-description": "Beschreiwung:",
+       "articleplaceholder-abouttopic-lua-reference": "Referenz"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/lt.json 
b/extensions/ArticlePlaceholder/i18n/lt.json
new file mode 100644
index 0000000..1373ad4
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/lt.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Zygimantus"
+               ]
+       },
+       "articleplaceholder-abouttopic-lua-identifier": "Identifikatorius"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/mk.json 
b/extensions/ArticlePlaceholder/i18n/mk.json
new file mode 100644
index 0000000..adfea08
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/mk.json
@@ -0,0 +1,23 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Bjankuloski06"
+               ]
+       },
+       "articleplaceholder-desc": "Дава службена страница со информации од 
{{WBREPONAME}} за извесна тема и покана за создавање на статија на таа тема",
+       "articleplaceholder-abouttopic": "За тема",
+       "articleplaceholder-abouttopic-intro": "Оваа службена страница создава 
содржинска страница за извесна тема во информации од {{WBREPONAME}}",
+       "articleplaceholder-abouttopic-entityid": "Внесете ја назнаката на 
единицата за да дибиете самосоздаден пополнувач за статија.",
+       "articleplaceholder-abouttopic-submit": "изработи",
+       "articleplaceholder-abouttopic-no-entity-error": "Ова не е важечка 
назнака на единицата.",
+       "articleplaceholder-abouttopic-create-article": "Создај нова статија со 
овој наслов",
+       "articleplaceholder-abouttopic-create-article-button": "Создај статија",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Поднеси",
+       "articleplaceholder-abouttopic-article-exists-error": "Веќе постои 
статија со тоа име.",
+       "articleplaceholder-abouttopic-lua-entity": "Единица",
+       "articleplaceholder-abouttopic-lua-description": "Опис:",
+       "articleplaceholder-abouttopic-lua-reference": "Навод",
+       "articleplaceholder-abouttopic-lua-qualifier": "Определница",
+       "articleplaceholder-abouttopic-lua-identifier": "Назнака",
+       "articleplaceholder-search-header": "Откријте ги податоците на темата"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/mr.json 
b/extensions/ArticlePlaceholder/i18n/mr.json
new file mode 100644
index 0000000..3f1ea96
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/mr.json
@@ -0,0 +1,12 @@
+{
+       "@metadata": {
+               "authors": [
+                       "V.narsikar"
+               ]
+       },
+       "articleplaceholder-abouttopic": "विषयाबद्दल",
+       "articleplaceholder-abouttopic-create-article-button": "लेख तयार करा",
+       "articleplaceholder-abouttopic-create-article-submit-button": "सादर 
करा",
+       "articleplaceholder-abouttopic-lua-description": "वर्णन:",
+       "articleplaceholder-abouttopic-lua-reference": "संदर्भ"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/ms.json 
b/extensions/ArticlePlaceholder/i18n/ms.json
new file mode 100644
index 0000000..c714a09
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/ms.json
@@ -0,0 +1,12 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Kurniasan"
+               ]
+       },
+       "articleplaceholder-desc": "Menyediakan laman khas berisi maklumat 
{{WBREPONAME}} berkenaan topik tertentu, beserta undangan mencipta rencana 
untuk topik terbabit",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Hantar",
+       "articleplaceholder-abouttopic-article-exists-error": "Sebuah rencana 
bernama sama telah wujud",
+       "articleplaceholder-abouttopic-lua-reference": "Rujukan",
+       "articleplaceholder-search-header": "Temukan data berkenaan topik ini"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/oc.json 
b/extensions/ArticlePlaceholder/i18n/oc.json
new file mode 100644
index 0000000..8b433f2
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/oc.json
@@ -0,0 +1,22 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Jfblanc"
+               ]
+       },
+       "articleplaceholder-desc": "Porgís una pagina especiala d'informacion 
de {{WBREPONAME}} sus un subjècte determinat, amb invitacion a crear un article 
sul subjècte.",
+       "articleplaceholder-abouttopic": "Sul subjècte",
+       "articleplaceholder-abouttopic-intro": "Aquesta pagina especiala genèra 
una pagina de contengut sus un subjècte determinat amb de donadas de 
{{WBREPONAME}}",
+       "articleplaceholder-abouttopic-entityid": "Picatz un identificador 
d'entitat per obténer un esquelèta d'article autogenerat",
+       "articleplaceholder-abouttopic-submit": "borrolhon",
+       "articleplaceholder-abouttopic-no-entity-error": "Aqueste identificador 
d'identitat es pas valid.",
+       "articleplaceholder-abouttopic-create-article": "Crear un article nòu 
amb lo títol",
+       "articleplaceholder-abouttopic-create-article-button": "Crear un 
article",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Sometre",
+       "articleplaceholder-abouttopic-article-exists-error": "Un article 
d'aquel nom ja existís",
+       "articleplaceholder-abouttopic-lua-entity": "Entitat",
+       "articleplaceholder-abouttopic-lua-reference": "Referéncia",
+       "articleplaceholder-abouttopic-lua-qualifier": "Calificador",
+       "articleplaceholder-abouttopic-lua-identifier": "Identificador",
+       "articleplaceholder-search-header": "Descobrir de donadas sobratz lo 
tèma"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/om.json 
b/extensions/ArticlePlaceholder/i18n/om.json
new file mode 100644
index 0000000..7788414
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/om.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Tumsaa"
+               ]
+       },
+       "articleplaceholder-abouttopic": "Waa'ee mataduree"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/pl.json 
b/extensions/ArticlePlaceholder/i18n/pl.json
new file mode 100644
index 0000000..ebcac81
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/pl.json
@@ -0,0 +1,11 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Chrumps"
+               ]
+       },
+       "articleplaceholder-abouttopic-create-article-button": "Utwórz artykuł",
+       "articleplaceholder-abouttopic-lua-description": "Opis:",
+       "articleplaceholder-abouttopic-lua-qualifier": "Kwalifikator",
+       "articleplaceholder-abouttopic-lua-identifier": "Identyfikator"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/ps.json 
b/extensions/ArticlePlaceholder/i18n/ps.json
new file mode 100644
index 0000000..384ac75
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/ps.json
@@ -0,0 +1,15 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Ahmed-Najib-Biabani-Ibrahimkhel"
+               ]
+       },
+       "articleplaceholder-abouttopic": "د موضوع په اړه",
+       "articleplaceholder-abouttopic-create-article": "په دې سرليک يوه نوې 
ليکنه ليکل",
+       "articleplaceholder-abouttopic-create-article-button": "يوه ليکنه ليکل",
+       "articleplaceholder-abouttopic-create-article-submit-button": "سپارل",
+       "articleplaceholder-abouttopic-article-exists-error": "په دې نوم يوه 
ليکنه له پخوا څخه شته.",
+       "articleplaceholder-abouttopic-lua-description": "څرگندونه:",
+       "articleplaceholder-abouttopic-lua-reference": "سرچينه",
+       "articleplaceholder-abouttopic-lua-identifier": "پېژندگر"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/qqq.json 
b/extensions/ArticlePlaceholder/i18n/qqq.json
new file mode 100644
index 0000000..a9848e7
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/qqq.json
@@ -0,0 +1,24 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Lucie-Aimée Kaffee",
+                       "Liuxinyu970226",
+                       "Raymond"
+               ]
+       },
+       "articleplaceholder-desc": 
"{{desc|what=extension|name=ArticlePlaceholder|url=https://www.mediawiki.org/wiki/Extension:ArticlePlaceholder}}\n{{WBREPONAME}}
 is a variable of the repository name of Wikidata (it has replaced the string 
'Wikidata').",
+       "articleplaceholder-abouttopic": "Title of Special:AboutTopic.",
+       "articleplaceholder-abouttopic-intro": "Intro paragraph shown on 
Special:AboutTopic.",
+       "articleplaceholder-abouttopic-entityid": "Text to encourage the user 
to enter an entity id.",
+       "articleplaceholder-abouttopic-submit": "Label on the submit 
button.\n{{Identical|Craft}}",
+       "articleplaceholder-abouttopic-no-entity-error": "Error message in case 
of an invalid entity id.",
+       "articleplaceholder-abouttopic-create-article": "Text in the popup 
encouraging the user to create an article with a selectable title",
+       "articleplaceholder-abouttopic-create-article-button": "Label on create 
article button",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Label on 
submit button\n{{Identical|Submit}}",
+       "articleplaceholder-abouttopic-article-exists-error": "Error to 
indicate the given article title already exists",
+       "articleplaceholder-abouttopic-lua-entity": "Header of the entity 
section\n{{Identical|Entity}}",
+       "articleplaceholder-abouttopic-lua-reference": "Header of the reference 
section\n{{Identical|Reference}}",
+       "articleplaceholder-abouttopic-lua-qualifier": "Header of the qualifier 
section\n{{Identical|Qualifier}}",
+       "articleplaceholder-abouttopic-lua-identifier": "Header of the 
identifier section\n{{Identical|Identifier}}",
+       "articleplaceholder-search-header": "Header in the search for the 
results of Special:AboutTopic generated pages"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/ru.json 
b/extensions/ArticlePlaceholder/i18n/ru.json
new file mode 100644
index 0000000..872a0f8
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/ru.json
@@ -0,0 +1,15 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Okras"
+               ]
+       },
+       "articleplaceholder-abouttopic": "О теме",
+       "articleplaceholder-abouttopic-create-article-button": "Создать статью",
+       "articleplaceholder-abouttopic-create-article-submit-button": 
"Отправить",
+       "articleplaceholder-abouttopic-article-exists-error": "Статья с таким 
названием уже существует.",
+       "articleplaceholder-abouttopic-lua-entity": "Сущность",
+       "articleplaceholder-abouttopic-lua-reference": "Примечание",
+       "articleplaceholder-abouttopic-lua-qualifier": "Квалификатор",
+       "articleplaceholder-abouttopic-lua-identifier": "Идентификатор"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/sd.json 
b/extensions/ArticlePlaceholder/i18n/sd.json
new file mode 100644
index 0000000..462facb
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/sd.json
@@ -0,0 +1,15 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Mehtab ahmed",
+                       "Aursani"
+               ]
+       },
+       "articleplaceholder-abouttopic": "موضوع بابت",
+       "articleplaceholder-abouttopic-create-article": "هن عنوان سان ڪو نئون 
مضمون تخليق ڪريو",
+       "articleplaceholder-abouttopic-create-article-button": "ڪو مضمون تخليق 
ڪريو",
+       "articleplaceholder-abouttopic-create-article-submit-button": "اماڻيو",
+       "articleplaceholder-abouttopic-article-exists-error": "هن نالي سان اڳ 
ئي هڪ مضمون موجود آهي",
+       "articleplaceholder-abouttopic-lua-reference": "حوالو",
+       "articleplaceholder-search-header": "موضوع تي مواد دريافت ڪريو"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/sr-ec.json 
b/extensions/ArticlePlaceholder/i18n/sr-ec.json
new file mode 100644
index 0000000..b4d7399
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/sr-ec.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Milicevic01"
+               ]
+       },
+       "articleplaceholder-abouttopic": "О теми"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/sr-el.json 
b/extensions/ArticlePlaceholder/i18n/sr-el.json
new file mode 100644
index 0000000..4f53b27
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/sr-el.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Milicevic01"
+               ]
+       },
+       "articleplaceholder-abouttopic": "O temi"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/su.json 
b/extensions/ArticlePlaceholder/i18n/su.json
new file mode 100644
index 0000000..6dd841a
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/su.json
@@ -0,0 +1,16 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Kandar"
+               ]
+       },
+       "articleplaceholder-desc": "Nyadiakeun kaca husus jeung {{WBREPONAME}} 
émbaran ngeunaan hiji jejer, kalayan uleman pikeun nyieun artikel pikeun éta 
jejer",
+       "articleplaceholder-abouttopic": "Ngeunaan Jejer",
+       "articleplaceholder-abouttopic-submit": "kriya",
+       "articleplaceholder-abouttopic-create-article": "Jieun artikel maké 
judul",
+       "articleplaceholder-abouttopic-create-article-button": "Jieun artikel",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Kirim",
+       "articleplaceholder-abouttopic-article-exists-error": "Artikel maké ieu 
judul geus aya",
+       "articleplaceholder-abouttopic-lua-entity": "Entitas",
+       "articleplaceholder-abouttopic-lua-reference": "Rujukan"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/sv.json 
b/extensions/ArticlePlaceholder/i18n/sv.json
new file mode 100644
index 0000000..3c4485b
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/sv.json
@@ -0,0 +1,16 @@
+{
+       "@metadata": {
+               "authors": [
+                       "WikiPhoenix",
+                       "Frisko"
+               ]
+       },
+       "articleplaceholder-abouttopic": "Om ämnet",
+       "articleplaceholder-abouttopic-no-entity-error": "Detta är inte ett 
giltigt artikel-ID.",
+       "articleplaceholder-abouttopic-create-article": "Skapa en ny artikel 
med titeln",
+       "articleplaceholder-abouttopic-create-article-button": "Skapa en 
artikel",
+       "articleplaceholder-abouttopic-create-article-submit-button": "Skicka",
+       "articleplaceholder-abouttopic-article-exists-error": "En artikel med 
detta namn finns redan",
+       "articleplaceholder-abouttopic-lua-entity": "Entitet",
+       "articleplaceholder-abouttopic-lua-reference": "Referens"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/tr.json 
b/extensions/ArticlePlaceholder/i18n/tr.json
new file mode 100644
index 0000000..9b939a4
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/tr.json
@@ -0,0 +1,9 @@
+{
+       "@metadata": {
+               "authors": [
+                       "HakanIST"
+               ]
+       },
+       "articleplaceholder-abouttopic": "Konu Hakkında",
+       "articleplaceholder-abouttopic-lua-identifier": "Tanımlayıcı"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/tt-cyrl.json 
b/extensions/ArticlePlaceholder/i18n/tt-cyrl.json
new file mode 100644
index 0000000..cda844d
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/tt-cyrl.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Ильнар"
+               ]
+       },
+       "articleplaceholder-abouttopic-lua-reference": "Искәрмә"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/yi.json 
b/extensions/ArticlePlaceholder/i18n/yi.json
new file mode 100644
index 0000000..135ed8e
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/yi.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "פוילישער"
+               ]
+       },
+       "articleplaceholder-abouttopic": "וועגן טעמע"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/zh-hans.json 
b/extensions/ArticlePlaceholder/i18n/zh-hans.json
new file mode 100644
index 0000000..5a15cdc
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/zh-hans.json
@@ -0,0 +1,23 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Liuxinyu970226"
+               ]
+       },
+       "articleplaceholder-desc": 
"提供包含有关特定主题的{{WBREPONAME}}信息的特殊页面,并带有邀请为主题创建条目的功能",
+       "articleplaceholder-abouttopic": "关于话题",
+       "articleplaceholder-abouttopic-intro": 
"此特殊页面通过使用{{WBREPONAME}}的信息,生成一段有关某一特定主题内容页面",
+       "articleplaceholder-abouttopic-entityid": "输入一个实体ID以获取自动生成的条目占位符。",
+       "articleplaceholder-abouttopic-submit": "工艺",
+       "articleplaceholder-abouttopic-no-entity-error": "这不是有效的实体ID。",
+       "articleplaceholder-abouttopic-create-article": "创建一个带标题的新条目",
+       "articleplaceholder-abouttopic-create-article-button": "创建条目",
+       "articleplaceholder-abouttopic-create-article-submit-button": "提交",
+       "articleplaceholder-abouttopic-article-exists-error": "已存在使用此名称的条目",
+       "articleplaceholder-abouttopic-lua-entity": "实体",
+       "articleplaceholder-abouttopic-lua-description": "描述:",
+       "articleplaceholder-abouttopic-lua-reference": "参考文献",
+       "articleplaceholder-abouttopic-lua-qualifier": "限定符",
+       "articleplaceholder-abouttopic-lua-identifier": "标识符",
+       "articleplaceholder-search-header": "发现数据在主题"
+}
diff --git a/extensions/ArticlePlaceholder/i18n/zh-hant.json 
b/extensions/ArticlePlaceholder/i18n/zh-hant.json
new file mode 100644
index 0000000..4d05cb0
--- /dev/null
+++ b/extensions/ArticlePlaceholder/i18n/zh-hant.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Liuxinyu970226"
+               ]
+       },
+       "articleplaceholder-fancyunicorn-create-article-submit-button": "送出"
+}
diff --git a/extensions/ArticlePlaceholder/includes/Hooks.php 
b/extensions/ArticlePlaceholder/includes/Hooks.php
new file mode 100644
index 0000000..99d599e
--- /dev/null
+++ b/extensions/ArticlePlaceholder/includes/Hooks.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace ArticlePlaceholder;
+
+/**
+ * File defining the hook handlers for the ArticlePlaceholder extension.
+ *
+ * @license GNU GPL v2+
+ * @author Lucie-Aimée Kaffee
+ */
+class Hooks {
+
+       /**
+        * External Lua libraries for Scribunto
+        *
+        * @param string $engine
+        * @param array &$extraLibraryPaths
+        *
+        * @return bool
+        */
+       public static function onScribuntoExternalLibraries(
+               $engine,
+               array &$extraLibraries
+       ) {
+               if ( $engine === 'lua' ) {
+                       
$extraLibraries['mw.ext.articlePlaceholder.entityRenderer'] = array(
+                               'class' => 
'ArticlePlaceholder\Lua\Scribunto_LuaArticlePlaceholderLibrary',
+                               'deferLoad' => true,
+                       );
+               }
+               return true;
+       }
+
+       /**
+        * External Lua library paths for Scribunto
+        *
+        * @param string $engine
+        * @param array &$extraLibraryPaths
+        *
+        * @return bool
+        */
+       public static function registerScribuntoExternalLibraryPaths(
+               $engine,
+               array &$extraLibraryPaths
+       ) {
+               if ( $engine === 'lua' ) {
+                       $extraLibraryPaths[] = __DIR__ . '/Lua';
+               }
+               return true;
+       }
+
+       /**
+        * @param array $files
+        * @return bool
+        */
+       public static function onUnitTestsList( array &$files ) {
+               $files[] = __DIR__ . '/../tests/phpunit/';
+               return true;
+       }
+}
diff --git a/extensions/ArticlePlaceholder/includes/Lua/Identifier.lua 
b/extensions/ArticlePlaceholder/includes/Lua/Identifier.lua
new file mode 100644
index 0000000..7be7163
--- /dev/null
+++ b/extensions/ArticlePlaceholder/includes/Lua/Identifier.lua
@@ -0,0 +1,6 @@
+-- All the identifier properties in one table
+-- As in http://tinyurl.com/wikidata-identifier on 21.11.2015
+-- created using https://github.com/frimelle/identifier-to-lua
+
+local table = {["P212"] = true, ["P213"] = true, ["P214"] = true, ["P218"] = 
true, ["P219"] = true, ["P220"] = true, ["P221"] = true, ["P227"] = true, 
["P229"] = true, ["P230"] = true, ["P232"] = true, ["P233"] = true, ["P236"] = 
true, ["P238"] = true, ["P239"] = true, ["P243"] = true, ["P244"] = true, 
["P245"] = true, ["P247"] = true, ["P267"] = true, ["P268"] = true, ["P269"] = 
true, ["P270"] = true, ["P271"] = true, ["P278"] = true, ["P303"] = true, 
["P305"] = true, ["P345"] = true, ["P349"] = true, ["P350"] = true, ["P351"] = 
true, ["P356"] = true, ["P359"] = true, ["P380"] = true, ["P381"] = true, 
["P396"] = true, ["P409"] = true, ["P424"] = true, ["P426"] = true, ["P434"] = 
true, ["P435"] = true, ["P436"] = true, ["P454"] = true, ["P455"] = true, 
["P474"] = true, ["P477"] = true, ["P480"] = true, ["P481"] = true, ["P492"] = 
true, ["P496"] = true, ["P497"] = true, ["P498"] = true, ["P502"] = true, 
["P508"] = true, ["P535"] = true, ["P536"] = true, ["P549"] = true, ["P586"] = 
true, ["P592"] = true, ["P593"] = true, ["P594"] = true, ["P595"] = true, 
["P597"] = true, ["P599"] = true, ["P604"] = true, ["P605"] = true, ["P617"] = 
true, ["P627"] = true, ["P632"] = true, ["P633"] = true, ["P635"] = true, 
["P638"] = true, ["P640"] = true, ["P646"] = true, ["P648"] = true, ["P649"] = 
true, ["P650"] = true, ["P651"] = true, ["P661"] = true, ["P677"] = true, 
["P679"] = true, ["P685"] = true, ["P686"] = true, ["P687"] = true, ["P691"] = 
true, ["P701"] = true, ["P704"] = true, ["P705"] = true, ["P709"] = true, 
["P717"] = true, ["P718"] = true, ["P721"] = true, ["P722"] = true, ["P723"] = 
true, ["P727"] = true, ["P745"] = true, ["P757"] = true, ["P759"] = true, 
["P760"] = true, ["P761"] = true, ["P762"] = true, ["P763"] = true, ["P764"] = 
true, ["P781"] = true, ["P791"] = true, ["P809"] = true, ["P815"] = true, 
["P818"] = true, ["P819"] = true, ["P827"] = true, ["P829"] = true, ["P830"] = 
true, ["P836"] = true, ["P839"] = true, ["P842"] = true, ["P843"] = true, 
["P844"] = true, ["P845"] = true, ["P846"] = true, ["P850"] = true, ["P858"] = 
true, ["P860"] = true, ["P861"] = true, ["P863"] = true, ["P864"] = true, 
["P865"] = true, ["P866"] = true, ["P867"] = true, ["P882"] = true, ["P889"] = 
true, ["P893"] = true, ["P894"] = true, ["P897"] = true, ["P902"] = true, 
["P905"] = true, ["P906"] = true, ["P907"] = true, ["P909"] = true, ["P911"] = 
true, ["P932"] = true, ["P933"] = true, ["P938"] = true, ["P939"] = true, 
["P946"] = true, ["P947"] = true, ["P949"] = true, ["P950"] = true, ["P951"] = 
true, ["P954"] = true, ["P957"] = true, ["P959"] = true, ["P960"] = true, 
["P961"] = true, ["P962"] = true, ["P966"] = true, ["P980"] = true, ["P998"] = 
true, ["P999"] = true, ["P1003"] = true, ["P1004"] = true, ["P1005"] = true, 
["P1006"] = true, ["P1007"] = true, ["P1014"] = true, ["P1015"] = true, 
["P1017"] = true, ["P1022"] = true, ["P1025"] = true, ["P1042"] = true, 
["P1045"] = true, ["P1047"] = true, ["P1048"] = true, ["P1051"] = true, 
["P1053"] = true, ["P1055"] = true, ["P1058"] = true, ["P1067"] = true, 
["P1070"] = true, ["P1077"] = true, ["P1084"] = true, ["P1085"] = true, 
["P1133"] = true, ["P1138"] = true, ["P1146"] = true, ["P1150"] = true, 
["P1153"] = true, ["P1157"] = true, ["P1159"] = true, ["P1183"] = true, 
["P1185"] = true, ["P1186"] = true, ["P1187"] = true, ["P1188"] = true, 
["P1203"] = true, ["P1207"] = true, ["P1208"] = true, ["P1212"] = true, 
["P1213"] = true, ["P1214"] = true, ["P1222"] = true, ["P1223"] = true, 
["P1224"] = true, ["P1225"] = true, ["P1226"] = true, ["P1229"] = true, 
["P1230"] = true, ["P1232"] = true, ["P1233"] = true, ["P1236"] = true, 
["P1237"] = true, ["P1238"] = true, ["P1241"] = true, ["P1242"] = true, 
["P1243"] = true, ["P1245"] = true, ["P1248"] = true, ["P1251"] = true, 
["P1252"] = true, ["P1253"] = true, ["P1258"] = true, ["P1260"] = true, 
["P1263"] = true, ["P1265"] = true, ["P1266"] = true, ["P1267"] = true, 
["P1271"] = true, ["P1273"] = true, ["P1275"] = true, ["P1277"] = true, 
["P1280"] = true, ["P1284"] = true, ["P1285"] = true, ["P1286"] = true, 
["P1287"] = true, ["P1288"] = true, ["P1293"] = true, ["P1296"] = true, 
["P1297"] = true, ["P1307"] = true, ["P1309"] = true, ["P1311"] = true, 
["P1315"] = true, ["P1320"] = true, ["P1330"] = true, ["P1331"] = true, 
["P1338"] = true, ["P1341"] = true, ["P1364"] = true, ["P1367"] = true, 
["P1368"] = true, ["P1369"] = true, ["P1375"] = true, ["P1391"] = true, 
["P1394"] = true, ["P1396"] = true, ["P1407"] = true, ["P1409"] = true, 
["P1413"] = true, ["P1415"] = true, ["P1417"] = true, ["P1421"] = true, 
["P1422"] = true, ["P1428"] = true, ["P1430"] = true, ["P1438"] = true, 
["P1439"] = true, ["P1440"] = true, ["P1447"] = true, ["P1459"] = true, 
["P1461"] = true, ["P1463"] = true, ["P1466"] = true, ["P1467"] = true, 
["P1468"] = true, ["P1469"] = true, ["P1473"] = true, ["P1474"] = true, 
["P1483"] = true, ["P1529"] = true, ["P1541"] = true, ["P1551"] = true, 
["P1553"] = true, ["P1555"] = true, ["P1556"] = true, ["P1562"] = true, 
["P1563"] = true, ["P1564"] = true, ["P1565"] = true, ["P1566"] = true, 
["P1567"] = true, ["P1573"] = true, ["P1580"] = true, ["P1583"] = true, 
["P1584"] = true, ["P1601"] = true, ["P1602"] = true, ["P1607"] = true, 
["P1608"] = true, ["P1609"] = true, ["P1610"] = true, ["P1614"] = true, 
["P1616"] = true, ["P1627"] = true, ["P1644"] = true, ["P1648"] = true, 
["P1649"] = true, ["P1650"] = true, ["P1651"] = true, ["P1662"] = true, 
["P1663"] = true, ["P1665"] = true, ["P1666"] = true, ["P1667"] = true, 
["P1669"] = true, ["P1670"] = true, ["P1679"] = true, ["P1695"] = true, 
["P1700"] = true, ["P1702"] = true, ["P1707"] = true, ["P1708"] = true, 
["P1710"] = true, ["P1711"] = true, ["P1712"] = true, ["P1714"] = true, 
["P1715"] = true, ["P1717"] = true, ["P1726"] = true, ["P1727"] = true, 
["P1728"] = true, ["P1729"] = true, ["P1730"] = true, ["P1732"] = true, 
["P1733"] = true, ["P1738"] = true, ["P1741"] = true, ["P1745"] = true, 
["P1749"] = true, ["P1751"] = true, ["P1761"] = true, ["P1763"] = true, 
["P1769"] = true, ["P1770"] = true, ["P1771"] = true, ["P1772"] = true, 
["P1788"] = true, ["P1794"] = true, ["P1795"] = true, ["P1798"] = true, 
["P1799"] = true, ["P1800"] = true, ["P1802"] = true, ["P1804"] = true, 
["P1807"] = true, ["P1808"] = true, ["P1816"] = true, ["P1818"] = true, 
["P1819"] = true, ["P1822"] = true, ["P1825"] = true, ["P1826"] = true, 
["P1828"] = true, ["P1832"] = true, ["P1837"] = true, ["P1838"] = true, 
["P1839"] = true, ["P1842"] = true, ["P1847"] = true, ["P1848"] = true, 
["P1850"] = true, ["P1866"] = true, ["P1869"] = true, ["P1871"] = true, 
["P1874"] = true, ["P1882"] = true, ["P1890"] = true, ["P1895"] = true, 
["P1933"] = true, ["P1934"] = true, ["P1935"] = true, ["P1938"] = true, 
["P1939"] = true, ["P1940"] = true, ["P1946"] = true, ["P1947"] = true, 
["P1948"] = true, ["P1953"] = true, ["P1954"] = true, ["P1969"] = true, 
["P1970"] = true, ["P1982"] = true, ["P1983"] = true, ["P1984"] = true, 
["P1985"] = true, ["P1986"] = true, ["P1992"] = true, ["P1994"] = true, 
["P2002"] = true, ["P2003"] = true, ["P2005"] = true, ["P2013"] = true, 
["P2014"] = true, ["P2019"] = true, ["P2020"] = true, ["P2041"] = true, 
["P2042"] = true, ["P2070"] = true, ["P2074"] = true, ["P2080"] = true, 
["P2081"] = true, ["P2108"] = true, ["P2161"] = true, ["P2163"] = true, 
["P2167"] = true, ["P2168"] = true, ["P2174"] = true, ["P2180"] = true, 
["P2181"] = true, ["P2182"] = true, ["P2187"] = true, ["P2188"] = true, 
["P2189"] = true, ["P2191"] = true, ["P2192"] = true, ["P2193"] = true, 
["P2194"] = true, ["P2195"] = true, ["P2206"] = true, ["P2242"] = true, 
["P2252"] = true, ["P2272"] = true, ["P2273"] = true, ["P2323"] = true, 
["P2327"] = true, ["P2328"] = true, ["P2330"] = true, ["P2331"] = true, }
+ return table
diff --git 
a/extensions/ArticlePlaceholder/includes/Lua/Scribunto_LuaArticlePlaceholderLibrary.php
 
b/extensions/ArticlePlaceholder/includes/Lua/Scribunto_LuaArticlePlaceholderLibrary.php
new file mode 100644
index 0000000..9b27d25
--- /dev/null
+++ 
b/extensions/ArticlePlaceholder/includes/Lua/Scribunto_LuaArticlePlaceholderLibrary.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace ArticlePlaceholder\Lua;
+
+use RuntimeException;
+use Scribunto_LuaLibraryBase;
+
+/**
+ * Registers and defines functions needed by the Lua modules
+ *
+ * @licence GNU GPL v2+
+ * @author Lucie-Aimée Kaffee
+ */
+class Scribunto_LuaArticlePlaceholderLibrary extends Scribunto_LuaLibraryBase {
+
+       /**
+        * @return string[]
+        */
+       public function getImageProperty() {
+               global $wgArticlePlaceholderImageProperty;
+               if (
+                       !is_string( $wgArticlePlaceholderImageProperty ) ||
+                       $wgArticlePlaceholderImageProperty === ''
+               ) {
+                       throw new RuntimeException( 'Bad value in 
$wgArticlePlaceholderImageProperty' );
+               }
+               return array( $wgArticlePlaceholderImageProperty );
+       }
+
+       /**
+        * @return array
+        */
+       public function register() {
+               // These functions will be exposed to the Lua module.
+               // They are member functions on a Lua table which is private to 
the module, thus
+               // these can't be called from user code, unless explicitly 
exposed in Lua.
+               $lib = array(
+                       'getImageProperty' => array( $this, 'getImageProperty' 
),
+               );
+
+               return $this->getEngine()->registerInterface(
+                       __DIR__ . 
'/mw.ext.articlePlaceholder.entityRenderer.lua', $lib, array()
+               );
+       }
+}
diff --git 
a/extensions/ArticlePlaceholder/includes/Lua/mw.ext.articlePlaceholder.entityRenderer.lua
 
b/extensions/ArticlePlaceholder/includes/Lua/mw.ext.articlePlaceholder.entityRenderer.lua
new file mode 100644
index 0000000..b934ca4
--- /dev/null
+++ 
b/extensions/ArticlePlaceholder/includes/Lua/mw.ext.articlePlaceholder.entityRenderer.lua
@@ -0,0 +1,409 @@
+--[[
+       @license GNU GPL v2+
+       @author Lucie-Aimée Kaffee
+]]
+
+local entityrenderer = {}
+
+local util = require( 'libraryUtil' )
+local php = mw_interface
+
+entityrenderer.imageProperty = php.getImageProperty()
+local identifierProperties = require( 'Identifier' )
+
+local hasReferences = false
+
+-- Get the datavalue for a given property.
+-- @param String propertyId
+-- @return String datatype
+local getDatatype = function( propertyId )
+  local property = mw.wikibase.getEntity( propertyId )
+  return property['datatype']
+end
+
+----------------------------------- Implementation of Renderers 
-----------------------------------
+
+-- Render a label to the language of the local Wiki.
+-- @param string entityId
+-- @return string label or entityId if no label available
+local labelRenderer = function( entityId )
+  local label = mw.wikibase.label( entityId )
+  if label == nil then
+    label = entityId
+  end
+  return label
+end
+
+-- Returns a table of statements sorted by *something*
+-- @param table entity
+-- @return table of properties
+local statementSorter = function( entity )
+  -- @todo sort by *something*
+  -- @todo limit number of statements
+  return entity:getProperties()
+end
+
+-- Renders a given table of snaks.
+-- @param table snaks
+-- @return String result
+local snaksRenderer = function( snaks )
+  local result = ''
+  if snaks ~= nil and type( snaks ) == 'table' then
+    result = mw.wikibase.renderSnaks( snaks )
+  end
+  return result
+end
+
+-- Render a reference.
+-- @param table references
+-- @return String result
+local referenceRenderer = function( references )
+  local frame = mw:getCurrentFrame()
+  local referencesWikitext = {}
+  local referenceWikitext
+
+  if references ~= nil then
+    hasReferences = true
+    local i = 1
+    while references[i] do
+      for propRef, snakRef in pairs( references[i]['snaks'] ) do
+        referenceWikitext = "'''" .. labelRenderer( propRef ) .. "''': " .. 
snaksRenderer( snakRef )
+        table.insert( referencesWikitext, frame:extensionTag( 'ref', 
referenceWikitext ) )
+      end
+      i = i + 1
+    end
+  end
+
+  return table.concat( referencesWikitext, "" )
+end
+
+-- Render a qualifier.
+-- @param table qualifierSnak
+-- @return String result
+local qualifierRenderer = function( qualifierSnak )
+  local result = ''
+  if qualifierSnak ~= nil then
+    result = result .. '<h4>' .. mw.message.new( 
'articleplaceholder-abouttopic-lua-qualifier' ):plain() .. '</h4>'
+    for key, value in pairs(qualifierSnak) do
+      result = result .. "<p>'''" .. labelRenderer( key ) .. "''': "
+      result = result .. snaksRenderer( value ) .. '</p>'
+    end
+  end
+  return result
+end
+
+-- Render the image.
+-- @param String propertyId
+-- @return String renderedImage
+local imageStatementRenderer = function( statement, orientationImage )
+  local reference = ''
+  local qualifier = ''
+  local image = ''
+  if statement ~= nil then
+    for key, value in pairs( statement ) do
+      if key == 'mainsnak' then
+        image = mw.wikibase.renderSnak( value )
+      elseif key == 'references' then
+        reference = referenceRenderer( value )
+      elseif key == 'qualifiers' then
+        qualifier = qualifierRenderer( value )
+      end
+    end
+  end
+  local result = '[[File:' .. image .. '|thumb|' .. orientationImage .. 
'|200px|' .. reference .. ']]'
+  result = result .. qualifier
+  return result
+end
+
+-- Renders a statement.
+-- @param table statement
+-- @return string result
+local statementRenderer = function( statement )
+  local result = ''
+  local reference = ''
+  local qualifier = ''
+  local mainsnak = ''
+  if statement ~= nil then
+    for key, value in pairs( statement ) do
+      if key == 'mainsnak' then
+        mainsnak = mw.wikibase.renderSnak( value )
+      elseif key == 'references' then
+        reference = referenceRenderer( value )
+      elseif key == 'qualifiers' then
+        qualifier = qualifierRenderer( value )
+      end
+    end
+  end
+  result = result .. '<p><span class="articleplaceholder-value">' .. mainsnak 
.. '</span>' .. reference .. '</p>' .. qualifier
+  return result
+end
+
+-- Renders the best statements.
+-- @param table entity
+-- @param String propertyId
+-- @return string statement
+local bestStatementRenderer = function( entity, propertyId )
+  local statement = ''
+  local bestStatements = entity:getBestStatements( propertyId )
+  for _, stat in pairs( bestStatements ) do
+    if getDatatype( propertyId ) == "commonsMedia" then
+      statement = statement .. imageStatementRenderer( stat, "center" )
+    else
+      statement = statement .. statementRenderer(stat)
+    end
+  end
+  return statement
+end
+
+-- Render the identifier
+-- @return string identifier
+local identifierRenderer = function( entity, propertyId )
+  return bestStatementRenderer( entity, propertyId )
+end
+
+-- Render a list of identifier
+-- @param table entity
+-- @return string identifier
+local identifierListRenderer = function( entity )
+  local properties = entity:getProperties()
+  local identifierList = ''
+  if properties ~= nil then
+    for _, propertyId in pairs( properties ) do
+      if identifierProperties[propertyId] then
+        identifierList = identifierList .. '<div 
class="articleplaceholder-identifier">' .. '<h2>' .. labelRenderer( propertyId 
) .. '</h2>'
+        identifierList = identifierList .. identifierRenderer( entity, 
propertyId ) .. '</div>'
+      end
+    end
+  end
+  if identifierList ~= nil and identifierList ~= '' then
+    local div = '<div class="articleplaceholder-identifierlist">'
+    identifierList = div .. '<h1>' .. mw.message.new( 
'articleplaceholder-abouttopic-lua-identifier' ):plain() .. '</h1>' ..  
identifierList
+    return identifierList .. '</div>'
+  end
+  return ''
+end
+
+-- Render a list of statements.
+-- @param table entity
+-- @return string result
+local statementListRenderer = function( entity )
+  local result = ''
+  local properties = statementSorter( entity )
+  if properties ~= nil then
+    for _, propertyId in pairs( properties ) do
+      if propertyId ~= entityrenderer.imageProperty and not 
identifierProperties[propertyId] then
+        result = result .. '<div class="articleplaceholder-statement">'
+        result = result .. '<h2>' .. labelRenderer( propertyId ) .. '</h2>'
+        result = result .. bestStatementRenderer( entity, propertyId )
+        result = result .. '</div>'
+      end
+    end
+  end
+  return '<div class="articleplaceholder-statementgroup">' .. result .. 
'</div>'
+end
+
+-- Render the image.
+-- @param String propertyId
+-- @return String renderedImage
+local topImageRenderer = function( entity, propertyId, orientationImage )
+  local renderedImage = ''
+  if propertyId ~= nil then
+    local imageName = entity:formatPropertyValues( propertyId ).value
+    if imageName ~= nil and imageName ~= '' then
+      renderedImage = '[[File:' .. imageName .. '|thumb|' .. orientationImage 
.. ']]'
+      renderedImage = '<div class="articleplaceholder-topimage">' .. 
renderedImage .. '</div>'
+    end
+  end
+  return renderedImage
+end
+
+-- Render the description.
+-- @param String entityId
+-- @return String description
+local function descriptionRenderer( entityId )
+  local description = mw.wikibase.description( entityId )
+
+  if description ~= nil then
+    return '<div class="articleplaceholer-description"><p>' .. description .. 
'</p></div>'
+  else
+    return ''
+  end
+end
+
+-- Render an entity, method to call all renderer
+-- @param String entityId
+-- @return String result
+local renderEntity = function ( entityID )
+  local entity = mw.wikibase.getEntityObject( entityID )
+  local result = ''
+
+  local description = descriptionRenderer( entityID )
+  local image = topImageRenderer( entity, entityrenderer.imageProperty, 
"right" )
+  local identifier = identifierListRenderer( entity )
+  local entityResult = statementListRenderer( entity )
+
+  result = result .. '__NOTOC__'
+  if description ~= nil then
+    result = result .. description
+  end
+  result = result .. '<div class="articleplaceholder-sidebar">' .. image
+  result = result .. identifier .. '</div>'
+  if entityResult ~= '' then
+    result = result .. entityResult
+  end
+
+  if hasReferences then
+    result = result .. '<h1>' .. mw.message.new( 
'articleplaceholder-abouttopic-lua-reference' ):plain() .. '</h1>'
+  end
+
+  return result
+end
+
+
+-------------------------------------------------------------------------------------------------
+
+----------------------------------- Getter und Setter 
--------------------------------------------
+entityrenderer.getLabelRenderer = function()
+  return labelRenderer
+end
+
+entityrenderer.setLabelRenderer = function( newLabelRenderer )
+  util.checkType( 'setLabelRenderer', 1, newLabelRenderer, 'function' )
+  labelRenderer = newLabelRenderer
+end
+
+entityrenderer.getStatementSorter = function()
+  return statementSorter
+end
+
+entityrenderer.setStatementSorter = function( newStatementSorter )
+  util.checkType( 'setStatementSorter', 1, newStatementSorter, 'function' )
+  statementSorter = newStatementSorter
+end
+
+entityrenderer.getSnaksRenderer = function()
+  return snaksRenderer
+end
+
+entityrenderer.setSnaksRenderer = function( newsnaksRenderer )
+  util.checkType( 'setSnaksRenderer', 1, newsnaksRenderer, 'function' )
+  snaksRenderer = newSnaksRenderer
+end
+
+entityrenderer.getReferenceRenderer = function()
+  return referenceRenderer
+end
+
+entityrenderer.setReferenceRenderer = function( newReferenceRenderer )
+  util.checkType( 'setReferenceRenderer', 1, newReferenceRenderer, 'function' )
+  referenceRenderer = newReferenceRenderer
+end
+
+entityrenderer.getQualifierRenderer = function()
+  return qualifierRenderer
+end
+
+entityrenderer.setQualifierRenderer = function( newQualifierRenderer )
+  util.checkType( 'setQualifierRenderer', 1, newQualifierRenderer, 'function' )
+  qualifierRenderer = newQualifierRenderer
+end
+
+entityrenderer.getImageStatementRenderer = function()
+  return imageStatementRenderer
+end
+
+entityrenderer.setImageStatementRenderer = function( newImageStatementRenderer 
)
+  util.checkType( 'setImageStatementRenderer', 1, newImageStatementRenderer, 
'function' )
+  imageStatementRenderer = newImageStatementRenderer
+end
+
+entityrenderer.getStatementRenderer = function()
+  return statementRenderer
+end
+
+entityrenderer.setStatementRenderer = function( newStatementRenderer )
+  util.checkType( 'setStatementRenderer', 1, newStatementRenderer, 'function' )
+  statementRenderer = newStatementRenderer
+end
+
+entityrenderer.getBestStatementRenderer = function()
+  return bestStatementRenderer
+end
+
+entityrenderer.setBestStatementRenderer = function( newBestStatementRenderer )
+  util.checkType( 'setBestStatementRenderer', 1, newBestStatementRenderer, 
'function' )
+  bestStatementRenderer = newBestStatementRenderer
+end
+
+entityrenderer.getIdentifierRenderer = function()
+  return identifierRenderer
+end
+
+entityrenderer.setIdentifierRenderer = function( newIdentifierRenderer )
+  util.checkType( 'setIdentifierRenderer', 1, newIdentifierRenderer, 
'function' )
+  identifierRenderer = newIdentifierRenderer
+end
+
+entityrenderer.getIdentifierListRenderer = function()
+  return identifierListRenderer
+end
+
+entityrenderer.setIdentifierListRenderer = function( newIdentifierListRenderer 
)
+  util.checkType( 'setIdentifierListRenderer', 1, newIdentifierListRenderer, 
'function' )
+  identifierListRenderer = newIdentifierListRenderer
+end
+
+entityrenderer.getStatementListRenderer = function()
+  return statementListRenderer
+end
+
+entityrenderer.setStatementListRenderer = function( newStatementListRenderer )
+  util.checkType( 'setStatementListRenderer', 1, newStatementListRenderer, 
'function' )
+  statementListRenderer = newStatementListRenderer
+end
+
+entityrenderer.getTopImageRenderer = function()
+  return topImageRenderer
+end
+
+entityrenderer.setTopImageRenderer = function( newTopImageRenderer )
+  util.checkType( 'setTopImageRenderer', 1, newTopImageRenderer, 'function' )
+  topImageRenderer = newTopImageRenderer
+end
+
+entityrenderer.getDescriptionRenderer = function()
+  return descriptionRenderer
+end
+
+entityrenderer.setDescriptionRenderer = function( newDescriptionRenderer )
+  util.checkType( 'setDescriptionRenderer', 1, newDescriptionRenderer, 
'function' )
+  descriptionRenderer = newDescriptionRenderer
+end
+
+entityrenderer.getRenderEntity = function()
+  return renderEntity
+end
+
+entityrenderer.setRenderEntity = function( newRenderEntity )
+  util.checkType( 'setRenderEntity', 1, newRenderEntity, 'function' )
+  renderEntity = newRenderEntity
+end
+
+entityrenderer.getHasReferences = function()
+  return hasReferences
+end
+
+entityrenderer.setHasReferences = function( newHasReferences )
+  util.checkType( 'setHasReferences', 1, newHasReferences, 'boolean' )
+  hasReferences = newHasReferences
+end
+
+--------------------------------------------------------------------------------------------------
+
+-- render an entity
+entityrenderer.render = function(frame)
+  local entityID = mw.text.trim( frame.args[1] or "" )
+  return renderEntity( entityID )
+end
+
+return entityrenderer
diff --git a/extensions/ArticlePlaceholder/includes/SearchHookHandler.php 
b/extensions/ArticlePlaceholder/includes/SearchHookHandler.php
new file mode 100644
index 0000000..daa0a51
--- /dev/null
+++ b/extensions/ArticlePlaceholder/includes/SearchHookHandler.php
@@ -0,0 +1,158 @@
+<?php
+
+namespace ArticlePlaceholder;
+
+use OutputPage;
+use SpecialSearch;
+use Wikibase\Client\WikibaseClient;
+use Wikibase\Lib\Interactors\TermIndexSearchInteractor;
+use Wikibase\Lib\Interactors\TermSearchResult;
+use Wikibase\TermIndex;
+use Wikibase\TermIndexEntry;
+
+/**
+ * Adding results from ArticlePlaceholder to search
+ *
+ * @author Lucie-Aimée Kaffee
+ * @license GNU General Public Licence 2.0 or later
+ */
+class SearchHookHandler {
+
+       /**
+        * @var TermIndex
+        */
+       private $termIndex;
+
+       /**
+        * @var TermIndexSearchInteractor
+        */
+       private $termSearchInteractor;
+
+       /**
+        * @var string
+        */
+       private $languageCode;
+
+       /**
+        * @param string $language user language
+        *
+        * @return self
+        */
+       private static function newFromGlobalState( $language ) {
+               global $wgLanguageCode;
+
+               $wikibaseClient = WikibaseClient::getDefaultInstance();
+
+               return new self(
+                       $wikibaseClient->getStore()->getTermIndex(),
+                       $wikibaseClient->newTermSearchInteractor( $language ),
+                       $wgLanguageCode
+               );
+       }
+
+       /**
+        * @param TermIndex $termIndex
+        * @param TermIndexSearchInteractor $termSearchInteractor
+        * @param string $languageCode content language
+        */
+       public function __construct(
+               TermIndex $termIndex,
+               TermIndexSearchInteractor $termSearchInteractor,
+               $languageCode
+       ) {
+               $this->termIndex = $termIndex;
+               $this->termSearchInteractor = $termSearchInteractor;
+               $this->languageCode = $languageCode;
+       }
+
+       /**
+        * @param SpecialSearch $specialSearch
+        * @param OutputPage $output
+        * @param string|null $term
+        *
+        * @return bool
+        */
+       public static function onSpecialSearchResultsAppend(
+               SpecialSearch $specialSearch,
+               OutputPage $output,
+               $term
+       ) {
+               if ( $term === null || $term === '' ) {
+                       return;
+               }
+               // user language, not content language
+               $instance = self::newFromGlobalState( 
$specialSearch->getLanguage()->getCode() );
+               $instance->addToSearch( $specialSearch, $output, $term );
+               return true;
+       }
+
+       /**
+        * @param SpecialSearch $specialSearch
+        * @param OutputPage $output
+        * @param string $term
+        */
+       public function addToSearch( SpecialSearch $specialSearch, OutputPage 
$output, $term ) {
+               $searchResult = $this->getSearchResults( $term );
+               if ( $searchResult !== null ) {
+                       $output->addWikiText( $this->getSearchHeader() );
+
+                       $output->addWikiText( $searchResult );
+               }
+       }
+
+       /**
+        * @return string
+        */
+       private function getSearchHeader() {
+               $header = '==' . wfMessage( 'articleplaceholder-search-header' 
)->text() . '==';
+               return $header;
+       }
+
+       /**
+        * @param string $term
+        *
+        * @return string
+        */
+       private function getSearchResults( $term ) {
+               $searchResults = $this->searchEntities( $term );
+               $link = 'Special:AboutTopic/';
+               $wikitext = null;
+               foreach ( $searchResults as $searchResult ) {
+                       $wikitext .= '<div 
class="article-placeholder-searchResult">'
+                                               . $this->createResult( 
$searchResult, $link )
+                                               . '</div>';
+               }
+               return $wikitext;
+       }
+
+       /**
+        * @param TermSearchResult $searchResult
+        * @param string $link
+        *
+        * @return string
+        */
+       private function createResult( TermSearchResult $searchResult, $link ) {
+               $entityId = $searchResult->getEntityId();
+               $label = $searchResult->getDisplayLabel()->getText();
+               $description = 
$searchResult->getDisplayDescription()->getText();
+
+               return '[[' . $link . wfEscapeWikiText( $entityId ) . '|' . 
wfEscapeWikiText( $label )
+                       .']]: ' . wfEscapeWikiText( $description );
+       }
+
+       /**
+        * @param string $term
+        *
+        * @return TermSearchResult[]
+        */
+       private function searchEntities( $term ) {
+               $searchResults = $this->termSearchInteractor->searchForEntities(
+                       $term,
+                       $this->languageCode,
+                       'item',
+                       array( TermIndexEntry::TYPE_LABEL, 
TermIndexEntry::TYPE_ALIAS )
+               );
+               return $searchResults;
+       }
+
+}
diff --git 
a/extensions/ArticlePlaceholder/includes/Template/aboutTopic-template-module.xml
 
b/extensions/ArticlePlaceholder/includes/Template/aboutTopic-template-module.xml
new file mode 100644
index 0000000..cac14d8
--- /dev/null
+++ 
b/extensions/ArticlePlaceholder/includes/Template/aboutTopic-template-module.xml
@@ -0,0 +1,95 @@
+<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ 
http://www.mediawiki.org/xml/export-0.10.xsd"; version="0.10" xml:lang="en">
+  <siteinfo>
+    <sitename>hey-hey-wiki</sitename>
+    <dbname>my_wiki</dbname>
+    <base>http://localhost/core/index.php/Main_Page</base>
+    <generator>MediaWiki 1.27alpha</generator>
+    <case>first-letter</case>
+    <namespaces>
+      <namespace key="-2" case="first-letter">Media</namespace>
+      <namespace key="-1" case="first-letter">Special</namespace>
+      <namespace key="0" case="first-letter" />
+      <namespace key="1" case="first-letter">Talk</namespace>
+      <namespace key="2" case="first-letter">User</namespace>
+      <namespace key="3" case="first-letter">User talk</namespace>
+      <namespace key="4" case="first-letter">Hey-hey-wiki</namespace>
+      <namespace key="5" case="first-letter">Hey-hey-wiki talk</namespace>
+      <namespace key="6" case="first-letter">File</namespace>
+      <namespace key="7" case="first-letter">File talk</namespace>
+      <namespace key="8" case="first-letter">MediaWiki</namespace>
+      <namespace key="9" case="first-letter">MediaWiki talk</namespace>
+      <namespace key="10" case="first-letter">Template</namespace>
+      <namespace key="11" case="first-letter">Template talk</namespace>
+      <namespace key="12" case="first-letter">Help</namespace>
+      <namespace key="13" case="first-letter">Help talk</namespace>
+      <namespace key="14" case="first-letter">Category</namespace>
+      <namespace key="15" case="first-letter">Category talk</namespace>
+      <namespace key="120" case="first-letter">Item</namespace>
+      <namespace key="121" case="first-letter">Item talk</namespace>
+      <namespace key="122" case="first-letter">Property</namespace>
+      <namespace key="123" case="first-letter">Property talk</namespace>
+      <namespace key="828" case="first-letter">Module</namespace>
+      <namespace key="829" case="first-letter">Module talk</namespace>
+    </namespaces>
+  </siteinfo>
+  <page>
+    <title>Template:AboutTopic</title>
+    <ns>10</ns>
+    <id>30</id>
+    <revision>
+      <id>350</id>
+      <parentid>349</parentid>
+      <timestamp>2016-01-21T15:00:18Z</timestamp>
+      <contributor>
+        <ip>127.0.0.1</ip>
+      </contributor>
+      <model>wikitext</model>
+      <format>text/x-wiki</format>
+      <text xml:space="preserve" bytes="260">This template is part of the 
[https://www.mediawiki.org/wiki/Extension:ArticlePlaceholder ArticlePlaceholder 
extension]. If you want to adjust it, please consider making your changes 
upstream.
+&lt;onlyinclude&gt;{{#invoke:AboutTopic|showData|{{{1}}}}}&lt;/onlyinclude&gt;</text>
+      <sha1>f4z4fq5u00orujc7eknv3zljd19u9vy</sha1>
+    </revision>
+  </page>
+  <page>
+    <title>Module:AboutTopic</title>
+    <ns>828</ns>
+    <id>31</id>
+    <revision>
+      <id>354</id>
+      <parentid>353</parentid>
+      <timestamp>2016-01-22T21:22:29Z</timestamp>
+      <contributor>
+        <ip>127.0.0.1</ip>
+      </contributor>
+      <model>Scribunto</model>
+      <format>text/plain</format>
+      <text xml:space="preserve" bytes="204">local p = {}
+
+-- get the label of the local entity
+p.showData = function(frame)
+ entityRenderer = require( 'mw.ext.articlePlaceholder.entityRenderer' )
+ return entityRenderer.render( frame )
+end
+
+return p</text>
+      <sha1>mx55u3pffzrgm5zr0coh5ww9vqvv8ot</sha1>
+    </revision>
+  </page>
+  <page>
+    <title>Module:AboutTopic/doc</title>
+    <ns>828</ns>
+    <id>38</id>
+    <revision>
+      <id>346</id>
+      <parentid>345</parentid>
+      <timestamp>2016-01-20T15:02:01Z</timestamp>
+      <contributor>
+        <ip>127.0.0.1</ip>
+      </contributor>
+      <model>wikitext</model>
+      <format>text/x-wiki</format>
+      <text xml:space="preserve" bytes="190">This Module is part of the 
[https://www.mediawiki.org/wiki/Extension:ArticlePlaceholder ArticlePlaceholder 
extension]. If you want to adjust it, please consider making your changes 
upstream.</text>
+      <sha1>7r1o4e4er1o8eb3pxvaloqapgpucfbw</sha1>
+    </revision>
+  </page>
+</mediawiki>
\ No newline at end of file
diff --git 
a/extensions/ArticlePlaceholder/modules/ext.articleplaceholder.createArticle.js 
b/extensions/ArticlePlaceholder/modules/ext.articleplaceholder.createArticle.js
new file mode 100644
index 0000000..e755db7
--- /dev/null
+++ 
b/extensions/ArticlePlaceholder/modules/ext.articleplaceholder.createArticle.js
@@ -0,0 +1,106 @@
+/**
+ * @licence GNU GPL v2+
+ *
+ * @author Lucie-Aimée Kaffee
+ */
+
+( function ( $, mw, OO ) {
+
+       var titleInput;
+
+       function onSubmit() {
+               var titleRaw = titleInput.getValue(),
+                       api = new mw.Api();
+
+               api.get( { action: 'query', titles: titleRaw } ).done( function 
( data ) {
+                       var query = data.query,
+                               pageKeys = Object.keys( query.pages ),
+                               title,
+                               link;
+
+                       if ( titleRaw !== titleInput.getValue() ) {
+                               return;
+                       }
+
+                       if ( pageKeys[ 0 ] === '-1' ) {
+                               title = mw.Title.newFromUserInput( titleRaw, 0 
);
+                               link = '?title=' + encodeURIComponent( 
title.getNameText() ) + '&action=edit';
+                               link = mw.util.wikiScript() + link;
+                               document.location.href = link;
+                       } else {
+                               $( '#mw-article-placeholder-error' ).append(
+                                       '<p>' + mw.message( 
'articleplaceholder-abouttopic-article-exists-error' ).escaped() + '</p>'
+                               );
+                       }
+               } );
+
+               return false;
+       }
+
+       function onWikipageContent() {
+               var dialog,
+                       windowManager,
+                       button,
+                       submitButton,
+                       dialogContent
+;
+               titleInput = new OO.ui.TextInputWidget( {
+                       value: mw.config.get( 'apLabel' ),
+                       multiline: false,
+                       autosize: true
+               } );
+
+               submitButton = new OO.ui.ButtonWidget( {
+                       label: mw.message( 
'articleplaceholder-abouttopic-create-article-submit-button' ).text()
+               } );
+
+               dialogContent = $( '<p>' + mw.message( 
'articleplaceholder-abouttopic-create-article' ).escaped() + '</p>' );
+               dialogContent.append( titleInput.$element );
+               dialogContent.append( submitButton.$element );
+               dialogContent.append( '<div 
id="mw-article-placeholder-error"></div>' );
+
+               submitButton.on( 'click', onSubmit );
+
+               titleInput.on( 'change', function () {
+                       $( '#mw-article-placeholder-error' ).empty();
+               } );
+
+               titleInput.on( 'enter', function () {
+                       submitButton.emit( 'click' );
+               } );
+
+               function CreateArticleDialog( config ) {
+                       CreateArticleDialog.super.call( this, config ); // 
jshint:ignore
+               }
+               OO.inheritClass( CreateArticleDialog, OO.ui.Dialog );
+
+               // Customize the initialize() function: This is where to add 
content to the dialog body and set up event handlers.
+               CreateArticleDialog.prototype.initialize = function () {
+                       CreateArticleDialog.super.prototype.initialize.call( 
this ); // jshint:ignore
+                       this.content = new OO.ui.PanelLayout( { $: this.$, 
padded: true, expanded: false } );
+                       this.content.$element.append( dialogContent );
+                       this.$body.append( this.content.$element );
+               };
+
+               CreateArticleDialog.prototype.getBodyHeight = function () {
+                       return this.content.$element.outerHeight( true );
+               };
+
+               dialog = new CreateArticleDialog( {
+                       size: 'medium'
+               } );
+               windowManager = new OO.ui.WindowManager();
+               button = OO.ui.infuse( 'create-article-button' );
+
+               $( 'body' ).append( windowManager.$element );
+               // Add the window to the window manager using the addWindows() 
method.
+               windowManager.addWindows( [ dialog ] );
+
+               button.on( 'click', function () {
+                       windowManager.openWindow( dialog );
+               } );
+       }
+
+       mw.hook( 'wikipage.content' ).add( onWikipageContent );
+
+} )( jQuery, mediaWiki, OO );
diff --git 
a/extensions/ArticlePlaceholder/modules/ext.articleplaceholder.defaultDisplay.css
 
b/extensions/ArticlePlaceholder/modules/ext.articleplaceholder.defaultDisplay.css
new file mode 100644
index 0000000..5eb9aa3
--- /dev/null
+++ 
b/extensions/ArticlePlaceholder/modules/ext.articleplaceholder.defaultDisplay.css
@@ -0,0 +1,41 @@
+.articleplaceholder-statement {
+  display: inline-block;
+  border: 1px solid;
+  vertical-align: top;
+  padding: 10px;
+  margin: 20px;
+  width: 300px;
+}
+
+#bodyContent {
+  padding-top: 5%;
+  padding-right: 305px;
+}
+
+#create-article-button {
+  position: absolute;
+  top: 0px;
+  left: 10px;
+}
+
+.articleplaceholder-sidebar {
+  position: absolute;
+  right: 0px;
+  width: 20%;
+}
+
+.articleplaceholder-topimage {
+  float: right;
+}
+
+.articleplaceholder-identifierlist {
+  clear: both;
+}
+
+.articleplaceholder-statementgroup {
+  margin-top: 5%;
+}
+
+.articleplaceholder-value {
+  font-size: 150%;
+}
diff --git 
a/extensions/ArticlePlaceholder/modules/ext.articleplaceholder.defaultDisplaySmall.css
 
b/extensions/ArticlePlaceholder/modules/ext.articleplaceholder.defaultDisplaySmall.css
new file mode 100644
index 0000000..d7f1084
--- /dev/null
+++ 
b/extensions/ArticlePlaceholder/modules/ext.articleplaceholder.defaultDisplaySmall.css
@@ -0,0 +1,10 @@
+#bodyContent {
+  padding-top: 5%;
+  padding-right: 305px;
+}
+
+.articleplaceholder-sidebar, .articleplaceholder-statementgroup {
+  float: none;
+  position: static;
+  width: auto;
+}
diff --git a/extensions/ArticlePlaceholder/package.json 
b/extensions/ArticlePlaceholder/package.json
new file mode 100644
index 0000000..d86af25
--- /dev/null
+++ b/extensions/ArticlePlaceholder/package.json
@@ -0,0 +1,15 @@
+{
+  "name": "articleplaceholder",
+  "version": "0.0.0",
+  "scripts": {
+    "test": "grunt test"
+  },
+  "devDependencies": {
+    "grunt": "0.4.5",
+    "grunt-cli": "0.1.13",
+    "grunt-contrib-jshint": "0.11.2",
+    "grunt-banana-checker": "0.4.0",
+    "grunt-jscs": "2.1.0",
+    "grunt-jsonlint": "1.0.7"
+  }
+}
diff --git a/extensions/ArticlePlaceholder/phpcs.xml 
b/extensions/ArticlePlaceholder/phpcs.xml
new file mode 100644
index 0000000..409f3eb
--- /dev/null
+++ b/extensions/ArticlePlaceholder/phpcs.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<ruleset>
+       <rule ref="vendor/mediawiki/mediawiki-codesniffer/MediaWiki"/>
+       <file>.</file>
+       <arg name="extensions" value="php,php5,inc"/>
+       <arg name="encoding" value="utf8"/>
+       <exclude-pattern>vendor</exclude-pattern>
+       <rule ref="Squiz.Classes.ValidClassName.NotCamelCaps">
+               
<exclude-pattern>Scribunto_LuaArticlePlaceholderLibrary</exclude-pattern>
+       </rule>
+</ruleset>
diff --git 
a/extensions/ArticlePlaceholder/tests/phpunit/Specials/SpecialAboutTopicTest.php
 
b/extensions/ArticlePlaceholder/tests/phpunit/Specials/SpecialAboutTopicTest.php
new file mode 100644
index 0000000..e52d7b6
--- /dev/null
+++ 
b/extensions/ArticlePlaceholder/tests/phpunit/Specials/SpecialAboutTopicTest.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace ArticlePlaceholder\Tests;
+
+use ArticlePlaceholder\Specials\SpecialAboutTopic;
+use Language;
+use MediaWikiTestCase;
+use Wikibase\Client\Store\TitleFactory;
+
+/**
+ * @covers ArticlePlaceholder\Specials\SpecialAboutTopic
+ *
+ * @group ArticlePlaceholder
+ *
+ * @licence GNU GPL v2+
+ * @author Thiemo Mättig
+ */
+class SpecialAboutTopicTest extends MediaWikiTestCase {
+
+       protected function setUp() {
+               parent::setUp();
+
+               $this->setMwGlobals( array(
+                       'wgContLang' => Language::factory( 'qqx' )
+               ) );
+       }
+
+       public function testExecute() {
+               $termLookupFactory = $this->getMockBuilder(
+                       
'Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookupFactory' )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $instance = new SpecialAboutTopic(
+                       $this->getMock( 
'Wikibase\DataModel\Entity\EntityIdParser' ),
+                       $termLookupFactory,
+                       $this->getMock( 'Wikibase\Lib\Store\SiteLinkLookup' ),
+                       $this->getMock( 'SiteStore' ),
+                       new TitleFactory(),
+                       '',
+                       $this->getMock( 
'Wikibase\DataModel\Services\Lookup\EntityLookup' )
+               );
+
+               $instance->execute( '' );
+               $output = $instance->getOutput();
+               $this->assertSame( '(articleplaceholder-abouttopic)', 
$output->getPageTitle() );
+
+               $html = $output->getHTML();
+               $this->assertContains( 'id="ap-abouttopic-form1"', $html );
+               $this->assertContains( 'id="ap-abouttopic-entityid"', $html );
+               $this->assertContains( '(articleplaceholder-abouttopic-intro)', 
$html );
+               $this->assertContains( 
'(articleplaceholder-abouttopic-entityid)', $html );
+               $this->assertContains( 
'(articleplaceholder-abouttopic-submit)', $html );
+       }
+
+}
diff --git a/extensions/ArticlePlaceholder/tests/phpunit/includes/HooksTest.php 
b/extensions/ArticlePlaceholder/tests/phpunit/includes/HooksTest.php
new file mode 100644
index 0000000..925a5cd
--- /dev/null
+++ b/extensions/ArticlePlaceholder/tests/phpunit/includes/HooksTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace ArticlePlaceholder\Tests;
+
+use ArticlePlaceholder\Hooks;
+use PHPUnit_Framework_TestCase;
+
+/**
+ * @covers ArticlePlaceholder\Hooks
+ *
+ * @group ArticlePlaceholder
+ *
+ * @licence GNU GPL v2+
+ * @author Thiemo Mättig
+ */
+class HooksTest extends PHPUnit_Framework_TestCase {
+
+       public function testRegisterScribuntoExternalLibraryPaths() {
+               $instance = new Hooks();
+               $paths = array();
+               $this->assertTrue( 
$instance->registerScribuntoExternalLibraryPaths( 'lua', $paths ) );
+               $this->assertArrayHasKey( 0, $paths );
+               $this->assertStringEndsWith( '/includes/Lua', $paths[0] );
+       }
+
+}
diff --git 
a/extensions/ArticlePlaceholder/tests/phpunit/includes/SearchHookHandlerTest.php
 
b/extensions/ArticlePlaceholder/tests/phpunit/includes/SearchHookHandlerTest.php
new file mode 100644
index 0000000..1fac5e9
--- /dev/null
+++ 
b/extensions/ArticlePlaceholder/tests/phpunit/includes/SearchHookHandlerTest.php
@@ -0,0 +1,144 @@
+<?php
+
+namespace ArticlePlaceholder\Tests;
+
+use ArticlePlaceholder\SearchHookHandler;
+use MediaWikiTestCase;
+use OutputPage;
+use RequestContext;
+use Title;
+use Wikibase\DataModel\Entity\EntityId;
+use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\DataModel\Entity\PropertyId;
+use Wikibase\LanguageFallbackChainFactory;
+use Wikibase\Lib\Interactors\TermIndexSearchInteractor;
+use Wikibase\Store\BufferingTermLookup;
+use Wikibase\TermIndexEntry;
+use Wikibase\Test\MockTermIndex;
+
+/**
+ * @group ArticlePlaceholder
+ *
+ * @covers SearchHookHandler
+ *
+ * @licence GNU GPL v2+
+ * @author Lucie-Aimée Kaffee
+ */
+class SearchHookHandlerTest extends MediaWikiTestCase {
+
+       private function getMockTermIndex() {
+               $typeLabel = TermIndexEntry::TYPE_LABEL;
+               $typeAlias = TermIndexEntry::TYPE_ALIAS;
+               $typeDescription = TermIndexEntry::TYPE_DESCRIPTION;
+
+               return new MockTermIndex(
+                       array(
+                               // Q111 - Has label, description and alias all 
the same
+                               $this->getTermIndexEntry( 'Unicorn', 'en', 
$typeLabel, new ItemId( 'Q111' ) ),
+                               $this->getTermIndexEntry( 'Unicorn', 'en', 
$typeDescription, new ItemId( 'Q111' ) ),
+                               $this->getTermIndexEntry( 'Unicorn', 'en', 
$typeAlias, new ItemId( 'Q111' ) ),
+                               $this->getTermIndexEntry( 'UNICORN', 'en', 
$typeAlias, new ItemId( 'Q111' ) ),
+                               // Q333
+                               $this->getTermIndexEntry( 'Unicorns are great', 
'en', $typeLabel, new ItemId( 'Q333' ) ),
+                               // Q555
+                               $this->getTermIndexEntry( 'Ta', 'en', 
$typeAlias, new ItemId( 'Q555' ) ),
+                               $this->getTermIndexEntry( 'Taa', 'en', 
$typeAlias, new ItemId( 'Q555' ) ),
+                               $this->getTermIndexEntry( 'TAAA', 'en-ca', 
$typeAlias, new ItemId( 'Q555' ) ),
+                               $this->getTermIndexEntry( 'Taa', 'en-ca', 
$typeAlias, new ItemId( 'Q555' ) ),
+                               // P22
+                               $this->getTermIndexEntry( 'Lama', 'en-ca', 
$typeLabel, new PropertyId( 'P22' ) ),
+                               $this->getTermIndexEntry( 'La-description', 
'en', $typeDescription, new PropertyId( 'P22' ) ),
+                               // P44
+                               $this->getTermIndexEntry( 'Lama', 'en', 
$typeLabel, new PropertyId( 'P44' ) ),
+                               $this->getTermIndexEntry( 'Lama-de-desc', 'de', 
$typeDescription, new PropertyId( 'P44' ) ),
+                       )
+               );
+       }
+
+       /**
+        * @param string $text
+        * @param string $languageCode
+        * @param string $termType
+        * @param EntityId|ItemId|PropertyId $entityId
+        *
+        * @returns TermIndexEntry
+        */
+       private function getTermIndexEntry( $text, $languageCode, $termType, 
EntityId $entityId ) {
+               return new TermIndexEntry( array(
+                       'termText' => $text,
+                       'termLanguage' => $languageCode,
+                       'termType' => $termType,
+                       'entityId' => $entityId->getNumericId(),
+                       'entityType' => $entityId->getEntityType(),
+               ) );
+       }
+
+       private function getMockedTermSearchInteractor( $language ) {
+               $termSearchInteractor = new TermIndexSearchInteractor(
+                       $this->getMockTermIndex(),
+                       new LanguageFallbackChainFactory,
+                       new BufferingTermLookup( $this->getMockTermIndex() ),
+                       $language
+               );
+               return $termSearchInteractor;
+       }
+
+       private function getSpecialSearch() {
+               $mock = $this->getMockBuilder( 'SpecialSearch' )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               return $mock;
+       }
+
+       private function getLanguageCode() {
+               return 'en';
+       }
+
+       protected function newSearchHookHandler() {
+               $language = $this->getLanguageCode();
+               $page = new SearchHookHandler(
+                       $this->getMockTermIndex(),
+                       $this->getMockedTermSearchInteractor( $language ),
+                       $language
+               );
+               return $page;
+       }
+
+       public function provideAddToSearch() {
+               return array(
+                       array(
+                               'get term, check if entity with right title is 
returned',
+                               'Unicorn',
+                               'Unicorn'
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider provideAddToSearch
+        */
+       public function testAddToSearch( $message, $term, $expected ) {
+               $specialSearch = $this->getSpecialSearch();
+               $output = new OutputPage( new RequestContext() );
+               $output->setTitle( Title::makeTitle( 0, 'testOutputSearch' ) );
+
+               $searchHookHander = $this->newSearchHookHandler();
+               $searchHookHander->addToSearch( $specialSearch, $output, $term 
);
+               $html = $output->getHTML();
+               $this->assertContains( $expected, $html, $message );
+       }
+
+       public function testOnSpecialSearchResultsAppend() {
+               $specialSearch = $this->getSpecialSearch();
+               $output = new OutputPage( new RequestContext() );
+
+               $result = SearchHookHandler::onSpecialSearchResultsAppend(
+                       $specialSearch,
+                       $output,
+                       ''
+               );
+
+               $this->assertNull( $result );
+       }
+
+}
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index a2de2bc..dcf3250 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -1568,5 +1568,39 @@
             "issues": "https://phabricator.wikimedia.org/";,
             "irc": "irc://irc.freenode.net/wikidata"
         }
+    },
+    {
+        "name": "mediawiki/article-placeholder",
+        "version": "dev-master",
+        "version_normalized": "9999999-dev",
+        "source": {
+            "type": "git",
+            "url": 
"https://github.com/wikimedia/mediawiki-extensions-ArticlePlaceholder.git";,
+            "reference": "d3fff7b3144c9ba020380f08018c225e42ce49d7"
+        },
+        "dist": {
+            "type": "zip",
+            "url": 
"https://api.github.com/repos/wikimedia/mediawiki-extensions-ArticlePlaceholder/zipball/d3fff7b3144c9ba020380f08018c225e42ce49d7";,
+            "reference": "d3fff7b3144c9ba020380f08018c225e42ce49d7",
+            "shasum": ""
+        },
+        "require-dev": {
+            "jakub-onderka/php-parallel-lint": "0.9.2",
+            "mediawiki/mediawiki-codesniffer": "0.5.1"
+        },
+        "time": "2016-02-08 12:46:34",
+        "type": "mediawiki-extension",
+        "installation-source": "dist",
+        "notification-url": "https://packagist.org/downloads/";,
+        "license": [
+            "GPL-2.0+"
+        ],
+        "authors": [
+            {
+                "name": "Lucie-Aimée Kaffee"
+            }
+        ],
+        "description": "Provides a special page with Wikibase information 
about a certain topic, with invitation to create an article for the topic",
+        "homepage": 
"https://www.mediawiki.org/wiki/Extension:ArticlePlaceholder";
     }
 ]

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia6cc31c92f6d044c9cccfaf9ec3a3f9805bf2e2e
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikidata
Gerrit-Branch: wmf/1.27.0-wmf.13
Gerrit-Owner: Aude <aude.w...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to