jenkins-bot has submitted this change and it was merged.

Change subject: New Wikidata Build - 2015-09-02T10:00:01+0000
......................................................................


New Wikidata Build - 2015-09-02T10:00:01+0000

Change-Id: I7b0d2f67988c9ab17c186c024cfee1954e48489b
---
M composer.lock
M extensions/Constraints/i18n/uk.json
A extensions/Quality/i18n/uk.json
M extensions/Wikibase/client/WikibaseClient.php
A extensions/Wikibase/client/i18n/bcl.json
M extensions/Wikibase/client/i18n/fr.json
M extensions/Wikibase/client/i18n/mk.json
M extensions/Wikibase/client/i18n/olo.json
M extensions/Wikibase/client/i18n/pt.json
M extensions/Wikibase/client/i18n/vec.json
M extensions/Wikibase/client/includes/InterwikiSorter.php
M extensions/Wikibase/client/includes/WikibaseClient.php
M extensions/Wikibase/client/tests/phpunit/includes/InterwikiSorterTest.php
M extensions/Wikibase/client/tests/phpunit/includes/WikibaseClientTest.php
M extensions/Wikibase/docs/constraints.wiki
A extensions/Wikibase/docs/datatypes.wiki
M extensions/Wikibase/docs/hooks.txt
A extensions/Wikibase/lib/WikibaseLib.datatypes.php
A extensions/Wikibase/lib/i18n/glk.json
M extensions/Wikibase/lib/i18n/nap.json
M extensions/Wikibase/lib/i18n/pt.json
A extensions/Wikibase/lib/includes/DataTypeDefinitions.php
M extensions/Wikibase/lib/includes/changes/EntityChangeFactory.php
M extensions/Wikibase/lib/includes/store/sql/SiteLinkTable.php
A extensions/Wikibase/lib/tests/phpunit/DataTypeDefinitionsTest.php
M extensions/Wikibase/lib/tests/phpunit/changes/EntityChangeFactoryTest.php
M extensions/Wikibase/lib/tests/phpunit/store/Sql/SiteLinkTableTest.php
M extensions/Wikibase/repo/Wikibase.php
A extensions/Wikibase/repo/WikibaseRepo.datatypes.php
M extensions/Wikibase/repo/i18n/bcl.json
M extensions/Wikibase/repo/i18n/nap.json
M extensions/Wikibase/repo/i18n/olo.json
M extensions/Wikibase/repo/i18n/vec.json
M extensions/Wikibase/repo/includes/BuilderBasedDataTypeValidatorFactory.php
M extensions/Wikibase/repo/includes/ValidatorBuilders.php
M extensions/Wikibase/repo/includes/ValueParserFactory.php
M extensions/Wikibase/repo/includes/WikibaseRepo.php
M extensions/Wikibase/repo/includes/api/ParseValue.php
M extensions/Wikibase/repo/includes/specials/SpecialItemByTitle.php
M extensions/Wikibase/repo/includes/specials/SpecialItemDisambiguation.php
M extensions/Wikibase/repo/tests/phpunit/includes/ValidatorBuildersTest.php
M extensions/Wikibase/repo/tests/phpunit/includes/ValueParserFactoryTest.php
M extensions/Wikibase/repo/tests/phpunit/includes/WikibaseRepoTest.php
M extensions/Wikibase/repo/tests/phpunit/includes/api/ParseValueTest.php
M extensions/Wikibase/repo/tests/phpunit/includes/content/EntityHandlerTest.php
M 
extensions/Wikibase/repo/tests/phpunit/includes/specials/SpecialItemByTitleTest.php
M vendor/composer/autoload_classmap.php
M vendor/composer/installed.json
48 files changed, 1,037 insertions(+), 351 deletions(-)

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



diff --git a/composer.lock b/composer.lock
index 13bc539..48a0cb5 100644
--- a/composer.lock
+++ b/composer.lock
@@ -911,7 +911,7 @@
             "source": {
                 "type": "git",
                 "url": 
"https://gerrit.wikimedia.org/r/mediawiki/extensions/WikibaseQualityConstraints";,
-                "reference": "d0e7eab7eb73920009e496cf3a2d9b9dfbf8be16"
+                "reference": "82a02aae853d042aa8293aabf29767580baba94c"
             },
             "require": {
                 "php": ">=5.3.0",
@@ -957,7 +957,7 @@
             "support": {
                 "issues": 
"https://phabricator.wikimedia.org/project/profile/1202/";
             },
-            "time": "2015-08-27 19:40:22"
+            "time": "2015-09-01 19:46:56"
         },
         {
             "name": "wikibase/data-model",
@@ -1293,7 +1293,7 @@
             "source": {
                 "type": "git",
                 "url": 
"https://gerrit.wikimedia.org/r/mediawiki/extensions/WikibaseQuality";,
-                "reference": "619c61d0cbf0f8c36804f820dc0570581eb0d42d"
+                "reference": "ae47f3e1baa725fef1c14825738a1510e733210b"
             },
             "require": {
                 "php": ">=5.3.0",
@@ -1337,7 +1337,7 @@
             "support": {
                 "issues": 
"https://phabricator.wikimedia.org/project/profile/989/";
             },
-            "time": "2015-08-29 19:48:01"
+            "time": "2015-09-01 19:46:52"
         },
         {
             "name": "wikibase/serialization-javascript",
@@ -1386,12 +1386,12 @@
             "source": {
                 "type": "git",
                 "url": 
"https://github.com/wikimedia/mediawiki-extensions-Wikibase.git";,
-                "reference": "c3a5e05eae970c8d19091ad6d5a535fed4276a6d"
+                "reference": "2a25cd4e403874e843591a0abf7ad5636b098894"
             },
             "dist": {
                 "type": "zip",
-                "url": 
"https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/c3a5e05eae970c8d19091ad6d5a535fed4276a6d";,
-                "reference": "c3a5e05eae970c8d19091ad6d5a535fed4276a6d",
+                "url": 
"https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/2a25cd4e403874e843591a0abf7ad5636b098894";,
+                "reference": "2a25cd4e403874e843591a0abf7ad5636b098894",
                 "shasum": ""
             },
             "require": {
@@ -1460,7 +1460,7 @@
                 "wikibaserepo",
                 "wikidata"
             ],
-            "time": "2015-09-01 09:30:08"
+            "time": "2015-09-02 02:58:03"
         },
         {
             "name": "wikibase/wikimedia-badges",
diff --git a/extensions/Constraints/i18n/uk.json 
b/extensions/Constraints/i18n/uk.json
index 00ecb4a..41543f1 100644
--- a/extensions/Constraints/i18n/uk.json
+++ b/extensions/Constraints/i18n/uk.json
@@ -1,8 +1,9 @@
 {
        "@metadata": {
                "authors": [
-                       "Максим Підліснюк"
+                       "Максим Підліснюк",
+                       "Dars"
                ]
        },
-       "wikidataquality-constraintreport": "Звіт по обмеженням"
+       "wbqc-constraintreport-explanation-part-two": "Обмеження розбираються 
із власних сторінок обговорення раз в тиждень, так що якщо ви додаєте, 
видаляєте або змінюєте обмеження, це може зайняти до тижня, поки зміни не 
будуть впроваджені. На даний момент ведуться роботи, щоб перенести обмеження на 
заявки про властивості, задіявши спеціальну сторінку перевірок в режимі 
реального часу."
 }
diff --git a/extensions/Quality/i18n/uk.json b/extensions/Quality/i18n/uk.json
new file mode 100644
index 0000000..4e4497e
--- /dev/null
+++ b/extensions/Quality/i18n/uk.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Dars"
+               ]
+       },
+       "wbq-desc": "Основне розширення для Якісних розширень Вікі-бази, які 
допомагають з керуванням суперечливих даних."
+}
diff --git a/extensions/Wikibase/client/WikibaseClient.php 
b/extensions/Wikibase/client/WikibaseClient.php
index 1fbb397..6e79fae 100644
--- a/extensions/Wikibase/client/WikibaseClient.php
+++ b/extensions/Wikibase/client/WikibaseClient.php
@@ -67,7 +67,9 @@
        global $wgExtensionCredits, $wgExtensionMessagesFiles, $wgHooks;
        global $wgAPIMetaModules, $wgAPIPropModules, $wgSpecialPages, 
$wgResourceModules;
        global $wgWBClientSettings, $wgRecentChangesFlags, $wgMessagesDirs;
-       global $wgJobClasses;
+       global $wgJobClasses, $wgWBClientDataTypes;
+
+       $wgWBClientDataTypes = require __DIR__ . 
'/../lib/WikibaseLib.datatypes.php';
 
        $wgExtensionCredits['wikibase'][] = array(
                'path' => __DIR__,
diff --git a/extensions/Wikibase/client/i18n/bcl.json 
b/extensions/Wikibase/client/i18n/bcl.json
new file mode 100644
index 0000000..a25273f
--- /dev/null
+++ b/extensions/Wikibase/client/i18n/bcl.json
@@ -0,0 +1,11 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Geopoet"
+               ]
+       },
+       "wikibase-comment-update": "{{WBREPONAME}} aytem pinagliwat",
+       "wikibase-rc-hide-wikidata-show": "Ipatanaw",
+       "wikibase-rc-wikibase-edit-letter": "D",
+       "wikibase-rc-wikibase-edit-title": "{{WBREPONAME}} liwaton"
+}
diff --git a/extensions/Wikibase/client/i18n/fr.json 
b/extensions/Wikibase/client/i18n/fr.json
index a85e5db..916bf49 100644
--- a/extensions/Wikibase/client/i18n/fr.json
+++ b/extensions/Wikibase/client/i18n/fr.json
@@ -71,6 +71,7 @@
        "wikibase-error-deserialize-error": "Échec à la désérialisation des 
données.",
        "wikibase-error-serialize-error": "Échec à la sérialisation des 
données",
        "wikibase-error-invalid-entity-id": "L’ID saisi est inconnu du système. 
Veuillez utiliser un ID d’entité valide.",
+       "wikibase-error-exceeded-entity-access-limit": "Trop d’entités 
{{WBREPONAME}} accédées.",
        "unconnectedpages": "Pages non reliées à un élément",
        "unconnectedpages-summary": "Cette page répertorie les pages non 
reliées à un élément de données (dans les espaces de noms qui prennent en 
charge les éléments connectés). La liste est triée par ID de page décroissant, 
afin que les nouvelles pages apparaissent en premier.",
        "wikibase-unconnectedpages-page": "Début de la liste des résultats avec 
la page :",
diff --git a/extensions/Wikibase/client/i18n/mk.json 
b/extensions/Wikibase/client/i18n/mk.json
index 2b9ad89..670ed54 100644
--- a/extensions/Wikibase/client/i18n/mk.json
+++ b/extensions/Wikibase/client/i18n/mk.json
@@ -58,6 +58,7 @@
        "wikibase-error-deserialize-error": "Не успеав да ги децентрализирам 
податоците",
        "wikibase-error-serialize-error": "Не успеав да ги серијализирам 
податоците",
        "wikibase-error-invalid-entity-id": "Назнаката не му е позната на 
системот. Внесете важечка назнака.",
+       "wikibase-error-exceeded-entity-access-limit": "Пристапени се премногу 
единици на {{WBREPONAME}}.",
        "unconnectedpages": "Страници што не се врзани со предмети",
        "unconnectedpages-summary": "Оваа страница без сврзан податочен предмет 
(во именски простори што поддржуваат сврзани предмети). Списокот е подреден 
надолно по назнака, од понови кон постари страници.",
        "wikibase-unconnectedpages-page": "Почни го списокот на резултати со 
страницата:",
diff --git a/extensions/Wikibase/client/i18n/olo.json 
b/extensions/Wikibase/client/i18n/olo.json
index bf10e75..33362ad 100644
--- a/extensions/Wikibase/client/i18n/olo.json
+++ b/extensions/Wikibase/client/i18n/olo.json
@@ -2,16 +2,18 @@
        "@metadata": {
                "authors": [
                        "Denö",
-                       "Ilja.mos"
+                       "Ilja.mos",
+                       "Mashoi7"
                ]
        },
        "wikibase-comment-update": "{{WBREPONAME}} on muutettu",
        "wikibase-dataitem": "{{WBREPONAME}} elementu",
-       "wikibase-editlinks": "Korjata linkit",
-       "wikibase-editlinkstitle": "Korjata kielienvälizet linkit",
+       "wikibase-editlinks": "Korjua linkit",
+       "wikibase-editlinkstitle": "Korjua kielienvälizet linkit",
        "wikibase-rc-hide-wikidata": "$1 {{WBREPONAME}}",
-       "wikibase-rc-hide-wikidata-hide": "Peittiä",
-       "wikibase-rc-hide-wikidata-show": "Ozuttua",
+       "wikibase-rc-hide-wikidata-hide": "Peitä",
+       "wikibase-rc-hide-wikidata-show": "Ozuta",
        "wikibase-rc-wikibase-edit-letter": "K",
-       "wikibase-rc-wikibase-edit-title": "{{WBREPONAME}} korjavus"
+       "wikibase-rc-wikibase-edit-title": "{{WBREPONAME}} korjavus",
+       "wikibase-otherprojects": "Muut projektat"
 }
diff --git a/extensions/Wikibase/client/i18n/pt.json 
b/extensions/Wikibase/client/i18n/pt.json
index f87d06c..b0e7748 100644
--- a/extensions/Wikibase/client/i18n/pt.json
+++ b/extensions/Wikibase/client/i18n/pt.json
@@ -13,7 +13,8 @@
                        "Vitorvicentevalente",
                        "Waldir",
                        555,
-                       "He7d3r"
+                       "He7d3r",
+                       "Fúlvio"
                ]
        },
        "wikibase-client-desc": "Cliente para a extensão Wikibase",
@@ -59,8 +60,8 @@
        "wikibase-replicationnote": "Por favor, saiba que pode levar vários 
minutos até que as mudanças são visíveis em todos as wikis.",
        "wikibase-watchlist-show-changes-pref": "Mostrar as edições no 
{{WBREPONAME}} na sua lista de páginas vigiadas",
        "wikibase-error-invalid-entity-id": "O identificador introduzido não é 
reconhecido pelo sistema. Utilize um identificador válido.",
-       "unconnectedpages": "Páginas não ligadas a itens",
-       "unconnectedpages-summary": "Esta lista contém páginas sem itens 
conectados. A lista está limitada aos domínios que suportam itens conectados.",
+       "unconnectedpages": "Páginas não conectadas a itens",
+       "unconnectedpages-summary": "Esta lista contém páginas sem itens 
conectados (em domínios com suporte a itens conectados). A lista está ordenada 
pelo ID da página descendente, de modo que as páginas mais novas são mostradas 
primeiro.",
        "wikibase-unconnectedpages-page": "Começar a lista de resultados com a 
página:",
        "wikibase-unconnectedpages-submit": "Ir",
        "wikibase-unconnectedpages-invalid-language": "\"$1\" não é um código 
de idioma válido.",
diff --git a/extensions/Wikibase/client/i18n/vec.json 
b/extensions/Wikibase/client/i18n/vec.json
index 83b14d8..e898763 100644
--- a/extensions/Wikibase/client/i18n/vec.json
+++ b/extensions/Wikibase/client/i18n/vec.json
@@ -11,7 +11,7 @@
        "wikibase-comment-linked": "Un elemento de Wikidata el xe stà colegà a 
sta pagina.",
        "wikibase-comment-unlink": "Sta pagina la xe stà destacà da l'elemento 
de Wikidata. I colegamenti interlenguìsteghi i xe stà cavà.",
        "wikibase-comment-restore": "L'elemento de Wikidata asocià el xe stà 
recuperà. I colegamenti interlenguìsteghi i xe stà ripristinà.",
-       "wikibase-comment-update": "Elemento Wikidata modificà",
+       "wikibase-comment-update": "Elemento {{WBREPONAME}} modificà",
        "wikibase-comment-sitelink-add": "Zontà colegamento lenguìstego: $1",
        "wikibase-comment-sitelink-change": "Colegamento lenguìstego canbià da 
$1 a $2",
        "wikibase-comment-sitelink-remove": "Cavà colegamento lenguìstego: $1",
@@ -39,7 +39,7 @@
        "wikibase-rc-hide-wikidata-show": "Mostra",
        "wikibase-rc-show-wikidata-pref": "Mostra le modifiche de Wikidata tra 
i ultimi canbiamenti",
        "wikibase-rc-wikibase-edit-letter": "D",
-       "wikibase-rc-wikibase-edit-title": "Modifica su Wikidata",
+       "wikibase-rc-wikibase-edit-title": "Modifica su {{WBREPONAME}}",
        "wikibase-replicationnote": "Podarìa volerghe calche minuto prima che i 
canbiamenti i se veda su tute le wiki.",
        "wikibase-watchlist-show-changes-pref": "Mostra le modifiche de 
Wikidata sui osservati speciali",
        "wikibase-error-invalid-entity-id": "L'ID specificà el xe sconossùo al 
sistema. Dòpara un ID de entità valido.",
diff --git a/extensions/Wikibase/client/includes/InterwikiSorter.php 
b/extensions/Wikibase/client/includes/InterwikiSorter.php
index 0497ab9..b70c9b7 100644
--- a/extensions/Wikibase/client/includes/InterwikiSorter.php
+++ b/extensions/Wikibase/client/includes/InterwikiSorter.php
@@ -134,7 +134,8 @@
                if ( $sort === 'alphabetic' ) {
                        // do nothing
                } elseif ( $sort === 'code' ) {
-                       sort( $sortOrder );
+                       // The concept of known/unknown languages is irrelevant 
in strict code order.
+                       $sortOrder = array();
                } else {
                        if ( array_key_exists( $sort, $sortOrders ) ) {
                                $sortOrder = $sortOrders[$sort];
diff --git a/extensions/Wikibase/client/includes/WikibaseClient.php 
b/extensions/Wikibase/client/includes/WikibaseClient.php
index 41dc4a4..2254217 100644
--- a/extensions/Wikibase/client/includes/WikibaseClient.php
+++ b/extensions/Wikibase/client/includes/WikibaseClient.php
@@ -6,6 +6,7 @@
 use DataValues\Deserializers\DataValueDeserializer;
 use Deserializers\Deserializer;
 use Exception;
+use Hooks;
 use Language;
 use LogicException;
 use MediaWikiSite;
@@ -47,6 +48,7 @@
 use Wikibase\LangLinkHandler;
 use Wikibase\LanguageFallbackChainFactory;
 use Wikibase\Lib\Changes\EntityChangeFactory;
+use Wikibase\Lib\DataTypeDefinitions;
 use Wikibase\Lib\FormatterLabelDescriptionLookupFactory;
 use Wikibase\Lib\LanguageNameLookup;
 use Wikibase\Lib\OutputFormatSnakFormatterFactory;
@@ -157,20 +159,26 @@
        private $restrictedEntityLookup = null;
 
        /**
-        * @since 0.4
-        *
+        * @var DataTypeDefinitions
+        */
+       private $dataTypeDefinitions;
+
+       /**
         * @param SettingsArray $settings
         * @param Language $contentLanguage
+        * @param DataTypeDefinitions $dataTypeDefinitions
         * @param SiteStore|null $siteStore
         */
        public function __construct(
                SettingsArray $settings,
                Language $contentLanguage,
+               DataTypeDefinitions $dataTypeDefinitions,
                SiteStore $siteStore = null
        ) {
                $this->settings = $settings;
                $this->contentLanguage = $contentLanguage;
                $this->siteStore = $siteStore;
+               $this->dataTypeDefinitions = $dataTypeDefinitions;
        }
 
        /**
@@ -180,21 +188,7 @@
         */
        public function getDataTypeFactory() {
                if ( $this->dataTypeFactory === null ) {
-                       // Temporary hack, will be removed in a follow-up
-                       $types = array(
-                               'commonsMedia'      => 'string',
-                               'globe-coordinate'  => 'globecoordinate',
-                               'monolingualtext'   => 'monolingualtext',
-                               'multilingualtext'  => 'multilingualtext',
-                               'quantity'          => 'quantity',
-                               'string'            => 'string',
-                               'time'              => 'time',
-                               'url'               => 'string',
-                               'wikibase-item'     => 'wikibase-entityid',
-                               'wikibase-property' => 'wikibase-entityid',
-                       );
-
-                       $this->dataTypeFactory = new DataTypeFactory( $types );
+                       $this->dataTypeFactory = new DataTypeFactory( 
$this->dataTypeDefinitions->getValueTypes() );
                }
 
                return $this->dataTypeFactory;
@@ -352,9 +346,16 @@
         * @return WikibaseClient
         */
        private static function newInstance() {
-               global $wgContLang;
+               global $wgContLang, $wgWBClientSettings, $wgWBClientDataTypes;
 
-               return new self( new SettingsArray( 
$GLOBALS['wgWBClientSettings'] ), $wgContLang );
+               $dataTypeDefinitions = $wgWBClientDataTypes;
+               Hooks::run( 'WikibaseClientDataTypes', array( 
&$dataTypeDefinitions ) );
+
+               return new self(
+                       new SettingsArray( $wgWBClientSettings ),
+                       $wgContLang,
+                       new DataTypeDefinitions( $dataTypeDefinitions )
+               );
        }
 
        /**
diff --git 
a/extensions/Wikibase/client/tests/phpunit/includes/InterwikiSorterTest.php 
b/extensions/Wikibase/client/tests/phpunit/includes/InterwikiSorterTest.php
index 78b5db7..e0d8243 100644
--- a/extensions/Wikibase/client/tests/phpunit/includes/InterwikiSorterTest.php
+++ b/extensions/Wikibase/client/tests/phpunit/includes/InterwikiSorterTest.php
@@ -94,6 +94,13 @@
                                array( 'e' ),
                                array( 'e', 'c', 'a', 'b', 'd', 'f' )
                        ),
+                       'Strict code order' => array(
+                               array( 'f', 'd', 'b', 'a', 'c', 'e' ),
+                               'code',
+                               array( 'alphabetic' => array( 'c', 'a' ) ), // 
this should be ignored
+                               array( 'e' ), // prepend
+                               array( 'e', 'a', 'b', 'c', 'd', 'f' )
+                       ),
                        array(
                                array( 'a', 'b', 'k', 'x' ),
                                'alphabetic',
diff --git 
a/extensions/Wikibase/client/tests/phpunit/includes/WikibaseClientTest.php 
b/extensions/Wikibase/client/tests/phpunit/includes/WikibaseClientTest.php
index d5e3015..a5776be 100644
--- a/extensions/Wikibase/client/tests/phpunit/includes/WikibaseClientTest.php
+++ b/extensions/Wikibase/client/tests/phpunit/includes/WikibaseClientTest.php
@@ -7,6 +7,7 @@
 use SiteStore;
 use Wikibase\Client\WikibaseClient;
 use Wikibase\DataModel\Entity\Item;
+use Wikibase\Lib\DataTypeDefinitions;
 use Wikibase\SettingsArray;
 use Wikibase\Test\MockSiteStore;
 
@@ -82,7 +83,7 @@
                $settings->setSetting( 'siteGlobalID', 'enwiki' );
                $settings->setSetting( 'languageLinkSiteGroup', 'wikipedia' );
 
-               $wikibaseClient = new WikibaseClient( $settings, 
Language::factory( 'en' ), $this->getSiteStore() );
+               $wikibaseClient = new WikibaseClient( $settings, 
Language::factory( 'en' ), new DataTypeDefinitions(), $this->getSiteStore() );
 
                $returnValue = $wikibaseClient->getLangLinkHandler();
                $this->assertInstanceOf( 'Wikibase\LangLinkHandler', 
$returnValue );
@@ -97,7 +98,7 @@
         * @dataProvider getLangLinkSiteGroupProvider
         */
        public function testGetLangLinkSiteGroup( $expected, SettingsArray 
$settings, SiteStore $siteStore ) {
-               $client = new WikibaseClient( $settings, Language::factory( 
'en' ), $siteStore );
+               $client = new WikibaseClient( $settings, Language::factory( 
'en' ), new DataTypeDefinitions(), $siteStore );
                $this->assertEquals( $expected, $client->getLangLinkSiteGroup() 
);
        }
 
@@ -125,7 +126,7 @@
         * @dataProvider getSiteGroupProvider
         */
        public function testGetSiteGroup( $expected, SettingsArray $settings, 
SiteStore $siteStore ) {
-               $client = new WikibaseClient( $settings, Language::factory( 
'en' ), $siteStore );
+               $client = new WikibaseClient( $settings, Language::factory( 
'en' ), new DataTypeDefinitions(), $siteStore );
                $this->assertEquals( $expected, $client->getSiteGroup() );
        }
 
@@ -251,7 +252,8 @@
        private function getWikibaseClient() {
                $settings = new SettingsArray( 
WikibaseClient::getDefaultInstance()->getSettings()->getArrayCopy() );
                $sites = new MockSiteStore( array() );
-               return new WikibaseClient( $settings, Language::factory( 'en' 
), $sites );
+               $dataTypeDefinitions = new DataTypeDefinitions();
+               return new WikibaseClient( $settings, Language::factory( 'en' 
), $dataTypeDefinitions, $sites );
        }
 
 }
diff --git a/extensions/Wikibase/docs/constraints.wiki 
b/extensions/Wikibase/docs/constraints.wiki
index 3fba88a..9f64d2c 100644
--- a/extensions/Wikibase/docs/constraints.wiki
+++ b/extensions/Wikibase/docs/constraints.wiki
@@ -29,9 +29,9 @@
 data integrity if an entity contains a "broken" reference.
 
 Soft constraints are enforced by the respective ChangeOps. Snak
-validation is largely based on the validators provided by the DataType
-objects which are constructed in WikibaseDataTypeBuilders, while the
-validators for terms come fro the TermValidatorFactory.
+validation is based on the validators provided by a DataTypeValidatorFactory
+(see datatypes.wiki for details), while the validators for terms come fro the
+TermValidatorFactory.
 
 Note that some soft constraints only require local knowledge of the
 value in questions, while others are "global" in that they apply to
diff --git a/extensions/Wikibase/docs/datatypes.wiki 
b/extensions/Wikibase/docs/datatypes.wiki
new file mode 100644
index 0000000..6219575
--- /dev/null
+++ b/extensions/Wikibase/docs/datatypes.wiki
@@ -0,0 +1,51 @@
+This document describes the concept of data types as used by Wikibase.
+
+== Overview ==
+Data types in Wikibase are rather insubstantial: they are modelled by DataType 
objects,
+but such objects do not define any functionality of themselves. They merely 
act as a type safe
+ID for the data type.
+
+Data types are used to declare which kinds of values can be associated with a 
Property in a
+Snak. For each data type, the following things are defined:
+
+* the type of DataValue to use for values
+* a localized name and description of the data type
+* ValueValidators that impose constraints on the allowed values
+* A ValueParser for parsing user input
+* Formatters for rendering values of the given type to various target formats.
+* RDF mappings for representing values of the given type in RDF.
+
+
+== Data Type Definitions ==
+Data types are defined in the global $wgWBRepoDataTypes and 
$wgWBClientDataTypes arrays,
+respectively. These arrays are constructed at bootstrap time in Wikibase.php 
resp.
+WikibaseClient.php based on the information returned when including the files
+WikibaseLib.datatypes.php, Wikibase.datatypes.php, and 
WikibaseClient.datatypes.php,
+respectively.
+
+$wgWBRepoDataTypes and $wgWBClientDataTypes are associative arrays that map 
data type IDs to a
+data type definition record. Each such record has the following fields:
+* value-type (repo and client): the data value type ID identifying the low 
level value type to use for this data type. Logically, the value type defines 
the structure of the value, while the data type defines constraints on the 
value.
+* validator-factory-callback (repo only): a callable that acts as a factory 
for the list of validators that should be used to check any user supplied 
values of the given data type. The callable will be called without any 
arguments, and must return a list of ValueValidator objects.
+* parser-factory-callback (repo only): a callable that acts as a factory for a 
ValueParser for this data type.
+* formatter-factory-callback (repo and client): (PLANNED) a callable that acts 
as a factory for ValueFormatters for use with this data type.
+* rdf-builder-factory-callback (repo only): (PLANNED) a callable that acts as 
a factory for DataValueRdfBuilder for use with this data type.
+
+Extensions that wish to register a data type should use the 
WikibaseRepoDataTypes
+resp. WikibaseClientDataTypes hooks to provide additional data type 
definitions.
+
+
+== Programmatic Access ==
+Information about data types can be accessed programmatically using the 
appropriate service objects.
+
+The data type definitions themselves are wrapped by a DataTypeDefinitions 
object; the DataType
+objects can be obtained from the DataTypeFactory service available via the 
getDataTypeFactory()
+method on WikibaseRepo and WikibaseClient.
+
+WikibaseRepo also defines the method getDataTypeValidatorFactory() which 
returns a
+DataTypeValidatorFactory for obtaining the validators for each data type.
+
+
+== Caveats ==
+* the Methods getSnakFormatterFactory() does not yet use 
$wgWikibaseDataTypeDefinitions.
+* RDF mappings for the different data types are still hardcoded.
diff --git a/extensions/Wikibase/docs/hooks.txt 
b/extensions/Wikibase/docs/hooks.txt
index a725b65..92e76fe 100644
--- a/extensions/Wikibase/docs/hooks.txt
+++ b/extensions/Wikibase/docs/hooks.txt
@@ -5,6 +5,11 @@
 
 == Repo ==
 
+'WikibaseRepoDataTypes': Called when constructing the top level WikibaseRepo 
factory;
+May be used to define additional data types. See also the 
WikibaseClientDataTypes hook.
+&$dataTypeDefinitions: the array of data type definitions, as defined by 
WikibaseRepo.datatypes.php.
+  Hook handlers may add additional definitions. See the datatypes.wiki file 
for details.
+
 'WikibaseTextForSearchIndex': Called by EntityContent::getTextForSearchIndex() 
to allow
 extra text to be passed to the search engine for indexing. If the hook 
function returns
 false, no text at all will be passed to the search index.
@@ -28,6 +33,11 @@
 
 == Client ==
 
+'WikibaseClientDataTypes': Called when constructing the top level 
WikibaseClient factory;
+May be used to define additional data types. See also the 
WikibaseRepoDataTypes hook.
+&$dataTypeDefinitions: the array of data type definitions, as defined by 
WikibaseClient.datatypes.php.
+  Hook handlers may add additional definitions. See the datatypes.wiki file 
for details.
+
 'WikibaseHandleChanges': Callend by ChangeHandler::handleChange() to allow 
pre-processing
 of changes.
 $changes: A list of Change objects
diff --git a/extensions/Wikibase/lib/WikibaseLib.datatypes.php 
b/extensions/Wikibase/lib/WikibaseLib.datatypes.php
new file mode 100644
index 0000000..7461f4d
--- /dev/null
+++ b/extensions/Wikibase/lib/WikibaseLib.datatypes.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Definition of data types for use with Wikibase.
+ * The array returned by the code below is supposed to be merged into 
$wgWBRepoDataTypes
+ * resp. $wgWBClientDataTypes. The basic definition contains only the 
'value-type' field.
+ *
+ * @note: When adding data types here, also add the corresponding information 
to
+ * repo/Wikibase.datatypes.php and client/WikibaseClient.datatypes.php
+ *
+ * @note: This is bootstrap code, it is executed for EVERY request. Avoid 
instantiating
+ * objects or loading classes here!
+ *
+ * @licence GNU GPL v2+
+ * @author Daniel Kinzler
+ */
+
+return array(
+       'commonsMedia'      => array( 'value-type' => 'string' ),
+       'globe-coordinate'  => array( 'value-type' => 'globecoordinate' ),
+       'monolingualtext'   => array( 'value-type' => 'monolingualtext' ),
+       'quantity'          => array( 'value-type' => 'quantity' ),
+       'string'            => array( 'value-type' => 'string' ),
+       'time'              => array( 'value-type' => 'time' ),
+       'url'               => array( 'value-type' => 'string' ),
+       'wikibase-item'     => array( 'value-type' => 'wikibase-entityid' ),
+       'wikibase-property' => array( 'value-type' => 'wikibase-entityid' ),
+);
diff --git a/extensions/Wikibase/lib/i18n/glk.json 
b/extensions/Wikibase/lib/i18n/glk.json
new file mode 100644
index 0000000..ee4d8af
--- /dev/null
+++ b/extensions/Wikibase/lib/i18n/glk.json
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "V6rg"
+               ]
+       },
+       "wikibase-sitelinks-wikipedia": "ويکيپديا"
+}
diff --git a/extensions/Wikibase/lib/i18n/nap.json 
b/extensions/Wikibase/lib/i18n/nap.json
index cf95a73..6c53aa0 100644
--- a/extensions/Wikibase/lib/i18n/nap.json
+++ b/extensions/Wikibase/lib/i18n/nap.json
@@ -27,11 +27,24 @@
        "wikibase-tooltip-error-details": "Dettaglie",
        "datatypes-type-wikibase-item": "Oggietto",
        "version-wikibase": "Wikibase",
-       "wikibase-time-precision-Gannum": "$1 miliarde 'e anne",
-       "wikibase-time-precision-Mannum": "$1 milione 'e anne",
-       "wikibase-time-precision-annum": "$1 anne",
+       "wikibase-time-precision-Gannum": "$1 miliarde 'e anne d.C.",
+       "wikibase-time-precision-Mannum": "$1 milione 'e anne d.C.",
+       "wikibase-time-precision-annum": "$1 anne d.C.",
        "wikibase-time-precision-millennium": "$1 millenne",
        "wikibase-time-precision-century": "$1 secule",
        "wikibase-time-precision-10annum": "anne $1",
-       "wikibase-item-summary-wbcreateredirect": "Redirezionate ncopp' a $4"
+       "wikibase-time-precision-BCE-Gannum": "$1 miliarde 'e anne a.C.",
+       "wikibase-time-precision-BCE-Mannum": "$1 milione 'e anne a.C.",
+       "wikibase-time-precision-BCE-annum": "$1 anne a.C.",
+       "wikibase-time-precision-BCE-millennium": "$1 millenne a.C.",
+       "wikibase-time-precision-BCE-century": "$1° secule a.C.",
+       "wikibase-time-precision-BCE-10annum": "anne $1 a.C.",
+       "wikibase-item-summary-wbsetitem": "Criato nu oggietto nuovo",
+       "wikibase-item-summary-wbcreate-new": "Criato nu oggietto nuovo",
+       "wikibase-item-summary-wbcreateredirect": "Redirezionate ncopp' a $4",
+       "wikibase-item-summary-wbeditentity": "Criato nu oggietto nuovo",
+       "wikibase-item-summary-wbeditentity-create": "Criato nu oggietto nuovo",
+       "wikibase-item-summary-wbeditentity-update": "Cangiato nu oggietto",
+       "wikibase-item-summary-clientsitelink-update": "Paggena spostata da 
[$3] a [$4]",
+       "wikibase-item-summary-clientsitelink-remove": "Paggena su [$3] 
canciellata"
 }
diff --git a/extensions/Wikibase/lib/i18n/pt.json 
b/extensions/Wikibase/lib/i18n/pt.json
index e84b7cf..87806b4 100644
--- a/extensions/Wikibase/lib/i18n/pt.json
+++ b/extensions/Wikibase/lib/i18n/pt.json
@@ -11,7 +11,8 @@
                        "Waldir",
                        "Sarilho1",
                        "He7d3r",
-                       "Imperadeiro90"
+                       "Imperadeiro90",
+                       "Fúlvio"
                ]
        },
        "wikibase-lib-desc": "Contém funcionalidades comuns para as extensões 
Wikibase e Wikibase Client",
@@ -80,12 +81,95 @@
        "datatypes-type-wikibase-property": "Propriedade",
        "datatypes-type-commonsMedia": "Ficheiro de média do Commons",
        "version-wikibase": "Wikibase",
-       "wikibase-time-precision-Gannum": "em  $1  biliões de anos",
-       "wikibase-time-precision-Mannum": "em $1 milhões de anos",
-       "wikibase-time-precision-annum": "em $1 anos",
+       "wikibase-time-precision-Gannum": "em  $1  bilhões de anos da EC",
+       "wikibase-time-precision-Mannum": "em $1 milhões de anos da EC",
+       "wikibase-time-precision-annum": "em $1 anos da EC",
        "wikibase-time-precision-millennium": "$1. milénio",
        "wikibase-time-precision-century": "$1. século",
        "wikibase-time-precision-10annum": "$1s",
        "wikibase-snakformatter-valuetype-mismatch": "Tipo do valor, \"$1\", 
não coincide com o tipo da propriedade, \"$2\".",
-       "wikibase-snakformatter-property-not-found": "Propriedade $1 não 
encontrada, não é possível determinar o tipo de dados a usar."
+       "wikibase-snakformatter-property-not-found": "Propriedade $1 não 
encontrada, não é possível determinar o tipo de dados a usar.",
+       "wikibase-item-summary-wbsetitem": "Novo item criado",
+       "wikibase-item-summary-wbcreate-new": "Novo item criado",
+       "wikibase-item-summary-wbcreateredirect": "Redirecionado para $4",
+       "wikibase-item-summary-wbeditentity": "Novo item criado",
+       "wikibase-item-summary-wbeditentity-create": "Novo item criado",
+       "wikibase-item-summary-wbeditentity-update": "Alteração de item",
+       "wikibase-item-summary-wbeditentity-override": "Eliminou um item",
+       "wikibase-item-summary-wbsetreference": "Definir uma fonte",
+       "wikibase-item-summary-wbsetreference-add": "Adicionou uma fonte à 
alegação",
+       "wikibase-item-summary-wbsetreference-set": "Alterou a fontes da 
alegação",
+       "wikibase-item-summary-wbsetlabel-add": "Adicionou o rótulo [$2]",
+       "wikibase-item-summary-wbsetlabel-set": "Rótulo [$2] alterado",
+       "wikibase-item-summary-wbsetlabel-remove": "Rótulo [$2] removido",
+       "wikibase-item-summary-wbsetdescription-add": "Descrição [$2] 
adicionada",
+       "wikibase-item-summary-wbsetdescription-set": "Descrição [$2] alterada",
+       "wikibase-item-summary-wbsetdescription-remove": "Descrição [$2] 
removida",
+       "wikibase-item-summary-wbsetaliases-set": "Definiu {{PLURAL:$1|nome 
alternativo|nomes alternativos}} [$2]",
+       "wikibase-item-summary-wbsetaliases-add-remove": "Adicionou ou removeu 
{{PLURAL:$1|nome alternativo|nomes alternativos}} [$2]",
+       "wikibase-item-summary-wbsetaliases-add": "Adicionou {{PLURAL:$1|nome 
alternativo|nomes alternativos}} [$2]",
+       "wikibase-item-summary-wbsetaliases-remove": "Removeu {{PLURAL:$1|nome 
alternativo|nomes alternativos}} [$2]",
+       "wikibase-item-summary-wbsetlabeldescriptionaliases": "Alterou o 
rótulo, descrição e nomes alternativos para [$2]",
+       "wikibase-item-summary-wbsetsitelink-add": "Adicionou ligação para 
[$2]",
+       "wikibase-item-summary-wbsetsitelink-add-both": "Adicionou ligação com 
emblema para [$2]",
+       "wikibase-item-summary-wbsetsitelink-set": "Ligação alterada para [$2]",
+       "wikibase-item-summary-wbsetsitelink-set-badges": "Alterou emblemas 
para [$2]",
+       "wikibase-item-summary-wbsetsitelink-set-both": "Alterou ligação e 
emblemas para [$2]",
+       "wikibase-item-summary-wbsetsitelink-remove": "Removeu ligação para 
[$2]",
+       "wikibase-item-summary-wblinktitles-create": "Criou este item para 
ligar as páginas",
+       "wikibase-item-summary-wblinktitles-connect": "Adicionou uma ligação de 
idioma para páginas ligadas",
+       "wikibase-item-summary-wbcreateclaim-value": "Criou {{PLURAL:$1|uma 
alegação|alegações}}",
+       "wikibase-item-summary-wbcreateclaim-novalue": "Criou {{PLURAL:$1|uma 
alegação|alegações}}",
+       "wikibase-item-summary-wbcreateclaim-somevalue": "Criou {{PLURAL:$1|uma 
alegação|alegações}}",
+       "wikibase-item-summary-wbcreateclaim": "Criou {{PLURAL:$1|uma 
alegação|alegações}}",
+       "wikibase-item-summary-wbsetclaimvalue": "Criou {{PLURAL:$1|valor de 
alegação|valores de alegações}}",
+       "wikibase-item-summary-wbremoveclaims": "Removeu {{PLURAL:$1|uma 
alegação|alegações}}",
+       "wikibase-item-summary-special-create-item": "Criou um item [$2] com 
{{PLURAL:$1|valor|valores}}",
+       "wikibase-item-summary-wbcreateclaim-create": "Alegação criada",
+       "wikibase-item-summary-wbremoveclaims-remove": "Removeu {{PLURAL:$1|uma 
alegação|alegações}}",
+       "wikibase-item-summary-wbsetclaim-update": "Alterou {{PLURAL:$3|uma 
alegação|alegações}}",
+       "wikibase-item-summary-wbsetclaim-create": "Criou {{PLURAL:$3|uma 
alegação|alegações}}",
+       "wikibase-item-summary-wbsetclaim-update-qualifiers": "Alterou 
{{PLURAL:$4|um qualificador|qualificadores}} de {{PLURAL:$3|uma 
alegação|alegações}}",
+       "wikibase-item-summary-wbsetclaim-update-references": "Alterou 
{{PLURAL:$4|uma referência|referências}} de {{PLURAL:$3|uma 
alegação|alegações}}",
+       "wikibase-item-summary-wbsetclaim-update-rank": "Alterou a 
classificação de {{PLURAL:$3|alegação|alegações}}",
+       "wikibase-item-summary-clientsitelink-update": "Página movida de [$3] 
para [$4]",
+       "wikibase-item-summary-clientsitelink-remove": "Página em [$3] 
eliminada",
+       "wikibase-item-summary-wbsetqualifier-add": "Adicionou {{PLURAL:$1|um 
qualificador|qualificadores}}",
+       "wikibase-item-summary-wbsetqualifier-update": "Alterou 
{{PLURAL:$1|qualificador|qualificadores}}",
+       "wikibase-item-summary-wbremovequalifiers-remove": "Removeu 
{{PLURAL:$1|um qualificador|qualificadores}}",
+       "wikibase-item-summary-wbremovereferences-remove": "Removeu 
{{PLURAL:$3|uma referência|referências}} de alegação",
+       "wikibase-item-summary-wbmergeitems-from": "Item fundido a partir de 
$3",
+       "wikibase-item-summary-wbmergeitems-to": "Item fundido com $3",
+       "wikibase-property-summary-wbcreate-new": "Criou uma nova propriedade",
+       "wikibase-property-summary-wbcreateclaim-create": "Alegação criada",
+       "wikibase-property-summary-wbcreateclaim": "Criou {{PLURAL:$1|uma 
alegação|alegações}}",
+       "wikibase-property-summary-wbsetclaimvalue": "Definiu {{PLURAL:$1|um 
valor de alegação|valores de alegação}}",
+       "wikibase-property-summary-wbsetreference": "Definiu uma referência",
+       "wikibase-property-summary-wbsetreference-add": "Adicionou uma 
referência à alegação",
+       "wikibase-property-summary-wbsetreference-set": "Alterou a referência 
da alegação",
+       "wikibase-property-summary-wbremoveclaims": "Removeu {{PLURAL:$1|uma 
alegação|alegações}}",
+       "wikibase-property-summary-wbremoveclaims-remove": "Removeu 
{{PLURAL:$1|uma alegação|alegações}}",
+       "wikibase-property-summary-wbeditentity-create": "Criou uma nova 
propriedade",
+       "wikibase-property-summary-wbeditentity-update": "Alterou a 
propriedade",
+       "wikibase-property-summary-wbsetlabel-add": "Adicionou o rótulo [$2]",
+       "wikibase-property-summary-wbsetlabel-set": "Alterou o rótulo [$2]",
+       "wikibase-property-summary-wbsetlabel-remove": "Removeu o rótulo [$2]",
+       "wikibase-property-summary-wbsetdescription-add": "Descrição [$2] 
adicionada",
+       "wikibase-property-summary-wbsetdescription-set": "Descrição [$2] 
alterada",
+       "wikibase-property-summary-wbsetdescription-remove": "Descrição [$2] 
removida",
+       "wikibase-property-summary-wbsetaliases-set": "Definiu {{PLURAL:$1|nome 
alternativo|nomes alternativos}} [$2]",
+       "wikibase-property-summary-wbsetaliases-add-remove": "Adicionou ou 
removeu {{PLURAL:$1|nome alternativo|nomes alternativos}} [$2]",
+       "wikibase-property-summary-wbsetaliases-add": "Adicionou 
{{PLURAL:$1|nome alternativo|nomes alternativos}} [$2]",
+       "wikibase-property-summary-wbsetaliases-remove": "Removeu 
{{PLURAL:$1|nome alternativo|nomes alternativos}} [$2]",
+       "wikibase-property-summary-wbsetlabeldescriptionaliases": "Alterou o 
rótulo, descrição e nomes alternativos para [$2]",
+       "wikibase-property-summary-wbsetclaim-update": "Alterou {{PLURAL:$3|uma 
alegação|alegações}}",
+       "wikibase-property-summary-wbsetclaim-create": "Criou {{PLURAL:$3|uma 
alegação|alegações}}",
+       "wikibase-property-summary-wbsetclaim-update-qualifiers": "Alterou 
{{PLURAL:$4|um qualificador|$4 qualificadores}} de {{PLURAL:$3|uma 
alegação|alegações}}",
+       "wikibase-property-summary-wbsetclaim-update-references": "Alterou 
{{PLURAL:$4|uma referência|referências}} de {{PLURAL:$3|uma 
alegação|alegações}}",
+       "wikibase-property-summary-wbsetclaim-update-rank": "Alterou a 
classificação de {{PLURAL:$3|alegação|alegações}}",
+       "wikibase-property-summary-wbsetqualifier-add": "Adicionou 
{{PLURAL:$1|um qualificador|qualificadores}}",
+       "wikibase-property-summary-wbsetqualifier-update": "Alterou 
{{PLURAL:$1|um qualificador|qualificadores}}",
+       "wikibase-property-summary-wbremovequalifiers-remove": "Removeu 
{{PLURAL:$1|um qualificador|qualificadores}}",
+       "wikibase-property-summary-wbremovereferences-remove": "Removeu 
{{PLURAL:$3|uma referência|referências}} da alegação",
+       "wikibase-property-summary-special-create-property": "Criou uma 
propriedade [$2] com {{PLURAL:$1|valor|valores}}"
 }
diff --git a/extensions/Wikibase/lib/includes/DataTypeDefinitions.php 
b/extensions/Wikibase/lib/includes/DataTypeDefinitions.php
new file mode 100644
index 0000000..5093874
--- /dev/null
+++ b/extensions/Wikibase/lib/includes/DataTypeDefinitions.php
@@ -0,0 +1,121 @@
+<?php
+
+namespace Wikibase\Lib;
+
+use Wikimedia\Assert\Assert;
+
+/**
+ * Service that manages data type definition. This is a registry that provides 
access to
+ * factory functions for various services associated with data types, such as 
validators,
+ * parsers, and formatters.
+ *
+ * DataTypeDefinitions provides a one-stop interface for defining data types. 
Each data type is defined
+ * using a "data type definition" array. A definition array has the following 
fields:
+ * - value-type: the value type used with the data type
+ * - validator-factory-callback: a callback for creating validators for the 
data type,
+ *   as used by BuilderBasedDataTypeValidatorFactory.
+ * @todo parser-factory-callback: a callback for instantiating a parser for 
the data type
+ * @todo formatter-factory-callback: a callback for instantiating a formatter 
for the data type
+ * @todo rdf-builder-factory-callback: a callback for instantiating a rdf 
mapping for the data type
+ *
+ * @see docs/datatypes.wiki
+ *
+ * @licence GNU GPL v2+
+ * @author Daniel Kinzler
+ */
+class DataTypeDefinitions {
+
+       /**
+        * @var array[]
+        */
+       private $dataTypeDefinitions = array();
+
+       /**
+        * @param array[] $dataTypeDefinitions An associative array mapping 
data type ids to data type
+        * definitions. Data type definitions are associative arrays, refer to 
the class level
+        * documentation.
+        */
+       public function __construct( $dataTypeDefinitions = array() ) {
+               Assert::parameterElementType( 'array', $dataTypeDefinitions, 
'$dataTypeDefinitions' );
+
+               $this->registerDataTypes( $dataTypeDefinitions );
+       }
+
+       /**
+        * Adds data type definitions. The new definitions are merged with the 
existing definitions.
+        * If a data type in $dataTypeDefinitions was already defined, the old 
definition is not
+        * replaced but the definitions are merged.
+        *
+        * @param array[] $dataTypeDefinitions An associative array mapping 
data type ids to data type
+        * definitions. Data type definitions are associative arrays, refer to 
the class level
+        * documentation.
+        */
+       public function registerDataTypes( array $dataTypeDefinitions ) {
+               Assert::parameterElementType( 'array', $dataTypeDefinitions, 
'$dataTypeDefinitions' );
+
+               foreach ( $dataTypeDefinitions as $id => $def ) {
+                       if ( isset( $this->dataTypeDefinitions[$id] ) ) {
+                               $this->dataTypeDefinitions[$id] = array_merge(
+                                       $this->dataTypeDefinitions[$id],
+                                       $dataTypeDefinitions[$id]
+                               );
+                       } else {
+                               $this->dataTypeDefinitions[$id] = 
$dataTypeDefinitions[$id];
+                       }
+               }
+       }
+
+       /**
+        * @return string[]
+        */
+       public function getTypeIds() {
+               return array_keys( $this->dataTypeDefinitions );
+       }
+
+       /**
+        * @param string $field
+        *
+        * @return array An associative array mapping data type IDs to the 
value of $field
+        * given in the original data type definition provided to the 
constructor.
+        */
+       private function getMapForDefinitionField( $field ) {
+               $fieldValues = array();
+
+               foreach ( $this->dataTypeDefinitions as $id => $def ) {
+                       if ( isset( $def[$field] ) ) {
+                               $fieldValues[$id] = $def[$field];
+                       }
+               }
+
+               return $fieldValues;
+       }
+
+       /**
+        * @return string[]
+        */
+       public function getValueTypes() {
+               return $this->getMapForDefinitionField( 'value-type' );
+       }
+
+       /**
+        * @see BuilderBasedDataTypeValidatorFactory
+        *
+        * @return callable[]
+        */
+       public function getValidatorFactoryCallbacks() {
+               return $this->getMapForDefinitionField( 
'validator-factory-callback' );
+       }
+
+       /**
+        * @see BuilderBasedDataTypeValidatorFactory
+        *
+        * @return callable[]|string[]
+        */
+       public function getParserFactoryCallbacks() {
+               return $this->getMapForDefinitionField( 
'parser-factory-callback' );
+       }
+
+       //TODO: getFormatterFactoryCallbacks()
+       //TODO: getRdfBuilderFactoryCallbacks()
+
+}
diff --git a/extensions/Wikibase/lib/includes/changes/EntityChangeFactory.php 
b/extensions/Wikibase/lib/includes/changes/EntityChangeFactory.php
index 06d9638..20b186a 100644
--- a/extensions/Wikibase/lib/includes/changes/EntityChangeFactory.php
+++ b/extensions/Wikibase/lib/includes/changes/EntityChangeFactory.php
@@ -8,6 +8,7 @@
 use Wikibase\DataModel\Entity\EntityDocument;
 use Wikibase\DataModel\Entity\EntityId;
 use Wikibase\DataModel\Services\Diff\EntityDiffer;
+use Wikibase\DataModel\Statement\StatementList;
 use Wikibase\EntityChange;
 use Wikibase\EntityFactory;
 
@@ -131,6 +132,11 @@
                        $theEntity = $newEntity;
                }
 
+               // don't include statements diff, since those are unused and 
not helpful
+               // performance-wise to the dispatcher and change handling.
+               $oldEntity->setStatements( new StatementList() );
+               $newEntity->setStatements( new StatementList() );
+
                $diff = $this->entityDiffer->diffEntities( $oldEntity, 
$newEntity );
 
                /**
diff --git a/extensions/Wikibase/lib/includes/store/sql/SiteLinkTable.php 
b/extensions/Wikibase/lib/includes/store/sql/SiteLinkTable.php
index 13b2b51..8c1785e 100644
--- a/extensions/Wikibase/lib/includes/store/sql/SiteLinkTable.php
+++ b/extensions/Wikibase/lib/includes/store/sql/SiteLinkTable.php
@@ -139,30 +139,26 @@
         *
         * @return boolean Success indicator
         */
-       public function insertLinksInternal( Item $item, $links, DatabaseBase 
$dbw ) {
+       public function insertLinksInternal( Item $item, array $links, 
DatabaseBase $dbw ) {
                wfDebugLog( __CLASS__, __FUNCTION__ . ': inserting links for ' 
. $item->getId()->getSerialization() );
 
-               $success = true;
-               foreach ( $links as $link ) {
-                       $success = $dbw->insert(
-                               $this->table,
-                               array(
-                                       'ips_item_id' => 
$item->getId()->getNumericId(),
-                                       'ips_site_id' => $link->getSiteId(),
-                                       'ips_site_page' => $link->getPageName()
-                               ),
-                               __METHOD__,
-                               array( 'IGNORE' )
+               $insert = array();
+               foreach ( $links as $siteLink ) {
+                       $insert[] = array(
+                               'ips_item_id' => $item->getId()->getNumericId(),
+                               'ips_site_id' => $siteLink->getSiteId(),
+                               'ips_site_page' => $siteLink->getPageName()
                        );
-
-                       $success = $success && $dbw->affectedRows();
-
-                       if ( !$success ) {
-                               break;
-                       }
                }
 
-               return $success;
+               $success = $dbw->insert(
+                       $this->table,
+                       $insert,
+                       __METHOD__,
+                       array( 'IGNORE' )
+               );
+
+               return $success && $dbw->affectedRows();
        }
 
        /**
@@ -179,26 +175,22 @@
         *
         * @return boolean Success indicator
         */
-       public function deleteLinksInternal( Item $item, $links, DatabaseBase 
$dbw ) {
+       public function deleteLinksInternal( Item $item, array $links, 
DatabaseBase $dbw ) {
                wfDebugLog( __CLASS__, __FUNCTION__ . ': deleting links for ' . 
$item->getId()->getSerialization() );
 
-               //TODO: We can do this in a single query by collecting all the 
site IDs into a set.
-
-               $success = true;
-               foreach ( $links as $link ) {
-                       $success = $dbw->delete(
-                               $this->table,
-                               array(
-                                       'ips_item_id' => 
$item->getId()->getNumericId(),
-                                       'ips_site_id' => $link->getSiteId()
-                               ),
-                               __METHOD__
-                       );
-
-                       if ( !$success ) {
-                               break;
-                       }
+               $siteIds = array();
+               foreach ( $links as $siteLink ) {
+                       $siteIds[] = $siteLink->getSiteId();
                }
+
+               $success = $dbw->delete(
+                       $this->table,
+                       array(
+                               'ips_item_id' => $item->getId()->getNumericId(),
+                               'ips_site_id' => $siteIds
+                       ),
+                       __METHOD__
+               );
 
                return $success;
        }
@@ -227,6 +219,7 @@
                );
 
                $this->releaseConnection( $dbw );
+
                return $ok;
        }
 
diff --git a/extensions/Wikibase/lib/tests/phpunit/DataTypeDefinitionsTest.php 
b/extensions/Wikibase/lib/tests/phpunit/DataTypeDefinitionsTest.php
new file mode 100644
index 0000000..cb91f88
--- /dev/null
+++ b/extensions/Wikibase/lib/tests/phpunit/DataTypeDefinitionsTest.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Wikibase\Lib\Tests;
+
+use Wikibase\Lib\DataTypeDefinitions;
+
+/**
+ * @covers Wikibase\Lib\DataTypeDefinitions
+ *
+ * @group DataValueExtensions
+ * @group WikibaseLib
+ * @group Wikibase
+ *
+ * @licence GNU GPL v2+
+ * @author Daniel Kinzler
+ */
+class DataTypeDefinitionsTest extends \MediaWikiTestCase {
+
+       private function getDataTypeDefinitions() {
+               $definitions = array(
+                       'foo' => array(
+                               'value-type' => 'FOO',
+                               'validator-factory-callback' => 
'DataTypeDefinitionsTest::getFooValidators',
+                               'parser-factory-callback' => 
'DataTypeDefinitionsTest::getFooParser',
+                               'formatter-factory-callback' => 
'DataTypeDefinitionsTest::getFooFormatter',
+                       ),
+                       'bar' => array(
+                               'value-type' => 'BAR',
+                               'formatter-factory-callback' => 
'DataTypeDefinitionsTest::getBarFormatter',
+                       )
+               );
+
+               return new DataTypeDefinitions( $definitions );
+       }
+
+       public function testTypeIds() {
+               $defs = $this->getDataTypeDefinitions();
+               $this->assertEquals( array( 'foo', 'bar' ), $defs->getTypeIds() 
);
+       }
+
+       public function testGetValueTypes() {
+               $defs = $this->getDataTypeDefinitions();
+               $this->assertEquals( array( 'foo' => 'FOO', 'bar' => 'BAR' ), 
$defs->getValueTypes() );
+       }
+
+       public function testGetValidatorFactoryCallbacks() {
+               $defs = $this->getDataTypeDefinitions();
+               $this->assertEquals( array( 'foo' => 
'DataTypeDefinitionsTest::getFooValidators' ), 
$defs->getValidatorFactoryCallbacks() );
+       }
+
+       public function testGetParserFactoryCallbacks() {
+               $defs = $this->getDataTypeDefinitions();
+               $this->assertEquals( array( 'foo' => 
'DataTypeDefinitionsTest::getFooParser' ), $defs->getParserFactoryCallbacks() );
+       }
+
+       public function testRegisterDataTypes() {
+               $defs = $this->getDataTypeDefinitions();
+
+               $extraTypes = array(
+                       'bar' => array(
+                               'validator-factory-callback' => 
'DataTypeDefinitionsTest::getBarValidators',
+                               'parser-factory-callback' => 
'DataTypeDefinitionsTest::getBarParser',
+                       ),
+                       'fuzz' => array(
+                               'value-type' => 'FUZZ',
+                               'validator-factory-callback' => 
'DataTypeDefinitionsTest::getFuzzValidators',
+                       )
+               );
+
+               $defs->registerDataTypes( $extraTypes );
+
+               $this->assertEquals( array( 'foo', 'bar', 'fuzz' ), 
$defs->getTypeIds() );
+               $this->assertEquals( array( 'foo' => 'FOO', 'bar' => 'BAR', 
'fuzz' => 'FUZZ' ), $defs->getValueTypes() );
+
+               $this->assertEquals(
+                       array( 'foo' => 
'DataTypeDefinitionsTest::getFooValidators',
+                               'bar' => 
'DataTypeDefinitionsTest::getBarValidators',
+                               'fuzz' => 
'DataTypeDefinitionsTest::getFuzzValidators' ),
+                       $defs->getValidatorFactoryCallbacks()
+               );
+       }
+
+}
diff --git 
a/extensions/Wikibase/lib/tests/phpunit/changes/EntityChangeFactoryTest.php 
b/extensions/Wikibase/lib/tests/phpunit/changes/EntityChangeFactoryTest.php
index f64e4ec..80530d8 100644
--- a/extensions/Wikibase/lib/tests/phpunit/changes/EntityChangeFactoryTest.php
+++ b/extensions/Wikibase/lib/tests/phpunit/changes/EntityChangeFactoryTest.php
@@ -2,6 +2,9 @@
 
 namespace Wikibase\Lib\Test\Change;
 
+use Diff\DiffOp\Diff\Diff;
+use Diff\DiffOp\DiffOpAdd;
+use Diff\DiffOp\DiffOpRemove;
 use Wikibase\ChangesTable;
 use Wikibase\DataModel\Entity\Entity;
 use Wikibase\DataModel\Entity\EntityId;
@@ -10,6 +13,10 @@
 use Wikibase\DataModel\Entity\Property;
 use Wikibase\DataModel\Entity\PropertyId;
 use Wikibase\DataModel\Services\Diff\EntityDiffer;
+use Wikibase\DataModel\SiteLink;
+use Wikibase\DataModel\Snak\PropertyNoValueSnak;
+use Wikibase\DataModel\Statement\Statement;
+use Wikibase\DataModel\Statement\StatementList;
 use Wikibase\EntityChange;
 use Wikibase\EntityFactory;
 use Wikibase\Lib\Changes\EntityChangeFactory;
@@ -26,6 +33,7 @@
  *
  * @licence GNU GPL v2+
  * @author Daniel Kinzler
+ * @author Katie Filbert < [email protected] >
  */
 class EntityChangeFactoryTest extends \PHPUnit_Framework_TestCase {
 
@@ -78,38 +86,118 @@
                $this->assertEquals( $entityId, $change->getEntityId() );
        }
 
-       public function newFromUpdateProvider() {
-               $item1 = new Item( new ItemId( 'Q1' ) );
-               $item2 = new Item( new ItemId( 'Q2' ) );
+       public function testNewFromUpdate() {
+               $itemId = new ItemId( 'Q1' );
 
-               $prop1 = Property::newFromType( 'string' );
-               $prop1->setId( new PropertyId( 'P1' ) );
+               $item = new Item( $itemId );
+               $item->setLabel( 'en', 'kitten' );
 
-               return array(
-                       'add item' => array( EntityChange::ADD, null, $item1, 
'wikibase-item~add' ),
-                       'update item' => array( EntityChange::UPDATE, $item1, 
$item2, 'wikibase-item~update' ),
-                       'remove property' => array( EntityChange::REMOVE, 
$prop1, null, 'wikibase-property~remove' ),
+               $updatedItem = new Item( $itemId );
+               $updatedItem->setLabel( 'en', 'kitten' );
+               $updatedItem->setLabel( 'es', 'gato' );
+
+               $factory = $this->getEntityChangeFactory();
+
+               $change = $factory->newFromUpdate( EntityChange::UPDATE, $item, 
$updatedItem );
+
+               $this->assertEquals( $itemId, $change->getEntityId(), 'entity 
id' );
+               $this->assertEquals( 'q1', $change->getObjectId(), 'object id' 
);
+               $this->assertEquals( 'wikibase-item~update', 
$change->getType(), 'type' );
+
+               $this->assertEquals(
+                       new Diff( array( 'es' => new DiffOpAdd( 'gato' ) ) ),
+                       $change->getDiff()->getLabelsDiff(),
+                       'diff'
                );
        }
 
-       /**
-        * @dataProvider newFromUpdateProvider
-        *
-        * @param string $action
-        * @param Entity $oldEntity
-        * @param Entity $newEntity
-        * @param string $expectedType
-        */
-       public function testNewFromUpdate( $action, $oldEntity, $newEntity, 
$expectedType ) {
+       public function testNewFromUpdate_add() {
+               $itemId = new ItemId( 'Q1' );
+
+               $item = new Item( $itemId );
+               $item->setLabel( 'en', 'kitten' );
+
+               $factory = $this->getEntityChangeFactory();
+               $change = $factory->newFromUpdate( EntityChange::ADD, null, 
$item );
+
+               $this->assertEquals( $itemId, $change->getEntityId(), 'entity 
id' );
+               $this->assertEquals( 'q1', $change->getObjectId(), 'object id' 
);
+               $this->assertEquals( 'wikibase-item~add', $change->getType(), 
'type' );
+
+               $this->assertEquals(
+                       new Diff( array( 'en' => new DiffOpAdd( 'kitten' ) ) ),
+                       $change->getDiff()->getLabelsDiff(),
+                       'diff'
+               );
+       }
+
+       public function testNewFromUpdate_remove() {
+               $propertyId = new PropertyId( 'P2' );
+
+               $property = new Property( $propertyId, null, 'string' );
+               $property->setLabel( 'de', 'Katze' );
+
+               $factory = $this->getEntityChangeFactory();
+               $change = $factory->newFromUpdate( EntityChange::REMOVE, 
$property, null );
+
+               $this->assertEquals( $propertyId, $change->getEntityId(), 
'entity id' );
+               $this->assertEquals( 'p2', $change->getObjectId(), 'object id' 
);
+               $this->assertEquals( 'wikibase-property~remove', 
$change->getType(), 'type' );
+
+               $this->assertEquals(
+                       new Diff( array( 'de' => new DiffOpRemove( 'Katze' ) ) 
),
+                       $change->getDiff()->getLabelsDiff(),
+                       'diff'
+               );
+       }
+
+       public function testNewFromUpdate_restore() {
+               $itemId = new ItemId( 'Q4' );
+
+               $item = new Item( $itemId );
+               $item->addSiteLink( new SiteLink( 'enwiki', 'Kitten' ) );
+
+               $factory = $this->getEntityChangeFactory();
+               $change = $factory->newFromUpdate( EntityChange::RESTORE, null, 
$item );
+
+               $this->assertEquals( $itemId, $change->getEntityId(), 'entity 
id' );
+               $this->assertEquals( 'q4', $change->getObjectId(), 'object id' 
);
+               $this->assertEquals( 'wikibase-item~restore', 
$change->getType(), 'type' );
+
+               $this->assertEquals(
+                       new Diff( array(
+                               'enwiki' => new Diff( array(
+                                       'name' => new DiffOpAdd( 'Kitten' )
+                               ) )
+                       ) ),
+                       $change->getDiff()->getSiteLinkDiff(),
+                       'diff'
+               );
+       }
+
+       public function testNewFromUpdate_excludeStatementsInDiffs() {
                $factory = $this->getEntityChangeFactory();
 
-               $entityId = ( $newEntity === null ) ? $oldEntity->getId() : 
$newEntity->getId();
+               $item = new Item( new ItemId( 'Q3' ) );
+               $statementList = new StatementList( array(
+                       new Statement( new PropertyNoValueSnak( 9000 ) )
+               ) );
 
-               $change = $factory->newFromUpdate( $action, $oldEntity, 
$newEntity );
+               $item->setStatements( $statementList );
 
-               $this->assertEquals( $action, $change->getAction() );
-               $this->assertEquals( $entityId, $change->getEntityId() );
-               $this->assertEquals( $expectedType, $change->getType() );
+               $updatedItem = new Item( new ItemId( 'Q3' ) );
+               $statementList = new StatementList( array(
+                       new Statement( new PropertyNoValueSnak( 10 ) )
+               ) );
+
+               $updatedItem->setStatements( $statementList );
+
+               $change = $factory->newFromUpdate( EntityChange::UPDATE, $item, 
$updatedItem );
+
+               $this->assertTrue(
+                       $change->getDiff()->isEmpty(),
+                       'Diff excludes statement changes and is empty'
+               );
        }
 
 }
diff --git 
a/extensions/Wikibase/lib/tests/phpunit/store/Sql/SiteLinkTableTest.php 
b/extensions/Wikibase/lib/tests/phpunit/store/Sql/SiteLinkTableTest.php
index 9361e99..5dbef22 100644
--- a/extensions/Wikibase/lib/tests/phpunit/store/Sql/SiteLinkTableTest.php
+++ b/extensions/Wikibase/lib/tests/phpunit/store/Sql/SiteLinkTableTest.php
@@ -24,7 +24,7 @@
        /**
         * @var SiteLinkTable
         */
-       protected $siteLinkTable;
+       private $siteLinkTable;
 
        protected function setUp() {
                parent::setUp();
@@ -76,9 +76,6 @@
                $this->assertFalse( $res );
        }
 
-       /**
-        * @dataProvider itemProvider
-        */
        public function testUpdateLinksOfItem() {
                // save initial links
                $item = new Item( new ItemId( 'Q177' ) );
@@ -98,10 +95,10 @@
 
                // check that the update worked correctly
                $actualLinks = $this->siteLinkTable->getSiteLinksForItem( 
$item->getId() );
-               $expectedLinks = $item->getSiteLinks();
+               $expectedLinks = $item->getSiteLinkList()->toArray();
 
                $missingLinks = array_udiff( $expectedLinks, $actualLinks, 
array( $this->siteLinkTable, 'compareSiteLinks' ) );
-               $extraLinks =   array_udiff( $actualLinks, $expectedLinks, 
array( $this->siteLinkTable, 'compareSiteLinks' ) );
+               $extraLinks = array_udiff( $actualLinks, $expectedLinks, array( 
$this->siteLinkTable, 'compareSiteLinks' ) );
 
                $this->assertEmpty( $missingLinks, 'Missing links' );
                $this->assertEmpty( $extraLinks, 'Extra links' );
@@ -114,8 +111,8 @@
        public function testGetSiteLinksOfItem( Item $item ) {
                $siteLinks = $this->siteLinkTable->getSiteLinksForItem( 
$item->getId() );
 
-               $this->assertEquals(
-                       $item->getSiteLinks(),
+               $this->assertArrayEquals(
+                       $item->getSiteLinkList()->toArray(),
                        $siteLinks
                );
        }
@@ -125,9 +122,7 @@
         * @dataProvider itemProvider
         */
        public function testGetItemIdForSiteLink( Item $item ) {
-               $siteLinks = $item->getSiteLinks();
-
-               foreach ( $siteLinks as $siteLink ) {
+               foreach ( $item->getSiteLinkList()->toArray() as $siteLink ) {
                        $this->assertEquals(
                                $item->getId(),
                                $this->siteLinkTable->getItemIdForSiteLink( 
$siteLink )
@@ -140,9 +135,7 @@
         * @dataProvider itemProvider
         */
        public function testGetItemIdForLink( Item $item ) {
-               $siteLinks = $item->getSiteLinks();
-
-               foreach ( $siteLinks as $siteLink ) {
+               foreach ( $item->getSiteLinkList()->toArray() as $siteLink ) {
                        $this->assertEquals(
                                $item->getId(),
                                $this->siteLinkTable->getItemIdForLink( 
$siteLink->getSiteId(), $siteLink->getPageName() )
@@ -164,4 +157,18 @@
                );
        }
 
+       /**
+        * @depends testSaveLinksOfItem
+        * @dataProvider itemProvider
+        */
+       public function testClear( Item $item ) {
+               $this->assertTrue(
+                       $this->siteLinkTable->clear() !== false
+               );
+
+               $this->assertEmpty(
+                       $this->siteLinkTable->getSiteLinksForItem( 
$item->getId() )
+               );
+       }
+
 }
diff --git a/extensions/Wikibase/repo/Wikibase.php 
b/extensions/Wikibase/repo/Wikibase.php
index 2dca3a8..444f587 100644
--- a/extensions/Wikibase/repo/Wikibase.php
+++ b/extensions/Wikibase/repo/Wikibase.php
@@ -84,6 +84,17 @@
        global $wgExtensionCredits, $wgGroupPermissions, 
$wgExtensionMessagesFiles, $wgMessagesDirs;
        global $wgAPIModules, $wgSpecialPages, $wgHooks, $wgAvailableRights;
        global $wgWBRepoSettings, $wgResourceModules, $wgValueParsers, 
$wgJobClasses;
+       global $wgWBRepoDataTypes;
+
+       $wgWBRepoDataTypes = require __DIR__ . 
'/../lib/WikibaseLib.datatypes.php';
+
+       $repoDatatypes = require __DIR__ . '/WikibaseRepo.datatypes.php';
+
+       // merge WikibaseRepo.datatypes.php into $wgWBRepoDataTypes
+       foreach ( $repoDatatypes as $type => $repoDef ) {
+               $baseDef = isset( $wgWBRepoDataTypes[$type] ) ? 
$wgWBRepoDataTypes[$type] : array();
+               $wgWBRepoDataTypes[$type] = array_merge( $baseDef, $repoDef );
+       }
 
        $wgExtensionCredits['wikibase'][] = array(
                'path' => __DIR__,
@@ -128,43 +139,17 @@
                );
        };
 
-       // all entity types use the same parser
-       $wgValueParsers['wikibase-item'] = $newEntityIdParser;
-       $wgValueParsers['wikibase-property'] = $newEntityIdParser;
+       /**
+        * @var callable[] $wgValueParsers Defines parser factory callbacks by 
parser name (not data type name).
+        * @deprecated use $wgWBRepoDataTypes instead.
+        */
+       $wgValueParsers['wikibase-entityid'] = 
$wgWBRepoDataTypes['wikibase-item']['parser-factory-callback'];
+       $wgValueParsers['globecoordinate'] = 
$wgWBRepoDataTypes['globe-coordinate']['parser-factory-callback'];
 
-       // deprecated: 'wikibase-entityid' is not a datatype. Alias kept for 
backwards compatibility.
-       $wgValueParsers['wikibase-entityid'] = $newEntityIdParser;
-
-       $wgValueParsers['quantity'] = function( ValueParsers\ParserOptions 
$options ) {
-               $language = Language::factory( $options->getOption( 
ValueParser::OPT_LANG ) );
-               $unlocalizer = new Wikibase\Lib\MediaWikiNumberUnlocalizer( 
$language );
-               return new \ValueParsers\QuantityParser( $options, $unlocalizer 
);
+       // 'null' is not a datatype. Kept for backwards compatibility.
+       $wgValueParsers['null'] = function() {
+               return new \ValueParsers\NullParser();
        };
-
-       $wgValueParsers['time'] = function( ValueParsers\ParserOptions $options 
) {
-               $factory = new Wikibase\Lib\Parsers\TimeParserFactory( $options 
);
-               return $factory->getTimeParser();
-       };
-
-       $wgValueParsers['globe-coordinate'] = 
'DataValues\Geo\Parsers\GlobeCoordinateParser';
-
-       // deprecated: 'globecoordinate' is not a datatype. Alias kept for 
backwards compatibility.
-       $wgValueParsers['globecoordinate'] = 
'DataValues\Geo\Parsers\GlobeCoordinateParser';
-
-       $wgValueParsers['monolingualtext'] = 
'Wikibase\Parsers\MonolingualTextParser';
-
-       // Use StringParser for datatypes that use StringValue
-       $stringParserFactoryFunction = function( ValueParsers\ParserOptions 
$options ) {
-               $normalizer = 
\Wikibase\Repo\WikibaseRepo::getDefaultInstance()->getStringNormalizer();
-               return new \ValueParsers\StringParser( new 
Wikibase\Lib\WikibaseStringValueNormalizer( $normalizer ) );
-       };
-
-       $wgValueParsers['commonsMedia'] = $stringParserFactoryFunction;
-       $wgValueParsers['string'] = $stringParserFactoryFunction;
-       $wgValueParsers['url'] = $stringParserFactoryFunction;
-
-       // deprecated: 'null' is not a datatype. Alias kept for backwards 
compatibility.
-       $wgValueParsers['null'] = 'ValueParsers\NullParser';
 
        // API module registration
        $wgAPIModules['wbgetentities'] = 'Wikibase\Repo\Api\GetEntities';
diff --git a/extensions/Wikibase/repo/WikibaseRepo.datatypes.php 
b/extensions/Wikibase/repo/WikibaseRepo.datatypes.php
new file mode 100644
index 0000000..99eed1a
--- /dev/null
+++ b/extensions/Wikibase/repo/WikibaseRepo.datatypes.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * Definition of data types for use with Wikibase.
+ * The array returned by the code below is supposed to be merged into 
$wgWBRepoDataTypes.
+ * It defines the formatters used by the repo to display data values of 
different types.
+ *
+ * @note: Keep in sync with lib/WikibaseLib.datatypes.php
+ *
+ * @note: This is bootstrap code, it is executed for EVERY request. Avoid 
instantiating
+ * objects or loading classes here!
+ *
+ * @note: 'validator-factory-callback' fields delegate to a global instance of
+ * ValidatorsBuilders.
+ *
+ * @see ValidatorsBuilders
+ *
+ * @licence GNU GPL v2+
+ * @author Daniel Kinzler
+ */
+
+use DataValues\Geo\Parsers\GlobeCoordinateParser;
+use ValueParsers\NullParser;
+use ValueParsers\QuantityParser;
+use ValueParsers\ValueParser;
+use Wikibase\Lib\EntityIdValueParser;
+use Wikibase\Lib\Parsers\TimeParserFactory;
+use Wikibase\Parsers\MonolingualTextParser;
+use Wikibase\Repo\WikibaseRepo;
+
+return call_user_func( function() {
+       // NOTE: 'validator-factory-callback' callbacks act as glue between the 
high level interface
+       // DataValueValidatorFactory and the low level factory for validators 
for well known data types,
+       // the ValidatorBuilders class.
+       // ValidatorBuilders should be used *only* here, program logic should 
use a
+       // DataValueValidatorFactory as returned by 
WikibaseRepo::getDataTypeValidatorFactory().
+
+       $newEntityIdParser = function( ValueParsers\ParserOptions $options ) {
+               $repo = WikibaseRepo::getDefaultInstance();
+               return new EntityIdValueParser( $repo->getEntityIdParser() );
+       };
+
+       $newNullParser = function( ValueParsers\ParserOptions $options ) {
+               return new NullParser();
+       };
+
+       return array(
+               'commonsMedia' => array(
+                       'validator-factory-callback' => function () {
+                               $factory = 
WikibaseRepo::getDefaultValidatorBuilders();
+                               return $factory->buildStringValidators();
+                       },
+                       'parser-factory-callback' => $newNullParser, //TODO: 
use StringParser
+
+               ),
+               'globe-coordinate' => array(
+                       'validator-factory-callback' => function () {
+                               $factory = 
WikibaseRepo::getDefaultValidatorBuilders();
+                               return $factory->buildCoordinateValidators();
+                       },
+                       'parser-factory-callback' => function( 
ValueParsers\ParserOptions $options ) {
+                               return new GlobeCoordinateParser( $options );
+                       }
+               ),
+               'monolingualtext' => array(
+                       'validator-factory-callback' => function () {
+                               $factory = 
WikibaseRepo::getDefaultValidatorBuilders();
+                               return 
$factory->buildMonolingualTextValidators();
+                       },
+                       'parser-factory-callback' => function( 
ValueParsers\ParserOptions $options ) {
+                               return new MonolingualTextParser( $options );
+                       }
+               ),
+               'quantity' => array(
+                       'validator-factory-callback' => function () {
+                               $factory = 
WikibaseRepo::getDefaultValidatorBuilders();
+                               return $factory->buildQuantityValidators();
+                       },
+                       'parser-factory-callback' => function( 
ValueParsers\ParserOptions $options ) {
+                               $language = Language::factory( 
$options->getOption( ValueParser::OPT_LANG ) );
+                               $unlocalizer = new 
Wikibase\Lib\MediaWikiNumberUnlocalizer( $language);
+                               return new QuantityParser( $options, 
$unlocalizer );
+                       },
+               ),
+               'string' => array(
+                       'validator-factory-callback' => function () {
+                               $factory = 
WikibaseRepo::getDefaultValidatorBuilders();
+                               return $factory->buildStringValidators();
+                       },
+                       'parser-factory-callback' => $newNullParser, //TODO: 
use StringParser
+               ),
+               'time' => array(
+                       'validator-factory-callback' => function () {
+                               $factory = 
WikibaseRepo::getDefaultValidatorBuilders();
+                               return $factory->buildTimeValidators();
+                       },
+                       'parser-factory-callback' => function( 
ValueParsers\ParserOptions $options ) {
+                               $factory = new TimeParserFactory( $options );
+                               return $factory->getTimeParser();
+                       },
+               ),
+               'url' => array(
+                       'validator-factory-callback' => function () {
+                               $factory = 
WikibaseRepo::getDefaultValidatorBuilders();
+                               return $factory->buildUrlValidators();
+                       },
+                       'parser-factory-callback' => $newNullParser, //TODO: 
use StringParser
+               ),
+               'wikibase-item' => array(
+                       'validator-factory-callback' => function () {
+                               $factory = 
WikibaseRepo::getDefaultValidatorBuilders();
+                               return $factory->buildItemValidators();
+                       },
+                       'parser-factory-callback' => $newEntityIdParser,
+               ),
+               'wikibase-property' => array(
+                       'validator-factory-callback' => function () {
+                               $factory = 
WikibaseRepo::getDefaultValidatorBuilders();
+                               return $factory->buildPropertyValidators();
+                       },
+                       'parser-factory-callback' => $newEntityIdParser,
+               ),
+       );
+
+});
diff --git a/extensions/Wikibase/repo/i18n/bcl.json 
b/extensions/Wikibase/repo/i18n/bcl.json
index 85c5d58..5866fb4 100644
--- a/extensions/Wikibase/repo/i18n/bcl.json
+++ b/extensions/Wikibase/repo/i18n/bcl.json
@@ -4,12 +4,13 @@
                        "Geopoet"
                ]
        },
+       "wikibase-edit": "liwaton",
+       "wikibase-add": "idugang",
        "wikibase-wikibaserepopage-unresolved-redirect": "$1 sarong 
pabalikwat.",
        "wikibase-setlabeldescriptionaliases-intro": "Ining porma minatugot 
saimo na magkaag nin panandaan, deskripsyon asin mga alyas kan entidad. Ika 
kaipo enot na magtao nin ID kan entidad (e.g. \"Q23\") asin sarong kodigo nin 
lengguwahe (e.g. \"en\").",
        "wikibase-setsitelink-introfull": "Ika nagkakaag nin pansityong 
saguysoy kan $2 para sa [[$1]].",
        "wikibase-setsitelink-submit": "Isusog an pansityong saguysoy",
        "wikibase-setsitelink-remove-failed": "An pansityong saguysoy dae tabi 
matatangkas.",
-       "wikibase-item-summary-wbmergeitems-to": "Pinagkasararong aytem 
pasiring sa \"$3\"",
        "wikibase-entity-not-viewable-title": "Tipo nin laman dae tarampad: Dae 
maipapahiling an laman",
        "wikibase-entity-not-viewable": "An itinaong laman kan tipong \"$1\" 
bako sarong Entidad asin dae maipagpahiling sa paagi kan datulan nin Wiki.",
        "apihelp-wbsetaliases-param-set": "Sarong listahan kan mga alyas na 
magriribay kan presenteng listahan (dae makukumbina dawa sa pagdugang o 
paghalion)"
diff --git a/extensions/Wikibase/repo/i18n/nap.json 
b/extensions/Wikibase/repo/i18n/nap.json
index b3aed0e..6379f5b 100644
--- a/extensions/Wikibase/repo/i18n/nap.json
+++ b/extensions/Wikibase/repo/i18n/nap.json
@@ -6,11 +6,14 @@
                        "Candalua"
                ]
        },
+       "wikibase-entity": "entità",
        "wikibase-entity-item": "oggietto",
+       "wikibase-entity-property": "proprietà",
        "wikibase-edit": "càgna",
        "wikibase-save": "sarva",
        "wikibase-cancel": "canciella",
        "wikibase-add": "azzecca",
+       
"wikibase-entitytermsview-entitytermsforlanguagelistview-configure-link-label": 
"Configura",
        "wikibase-entitytermsforlanguagelistview-description": "Descrizzione",
        "wikibase-entitytermsforlanguagelistview-label": "Etichetta",
        "wikibase-entitytermsforlanguagelistview-language": "Lengua",
@@ -30,6 +33,7 @@
        "wikibase-aliases-empty": "Nun se trovano ll'aliasse. Nun se so' 
definite.",
        "wikibase-statementview-rank-normal": "Classificato normale",
        "wikibase-statementview-referencesheading-pendingcountersubject": 
"{{PLURAL:$1|riferimento|riferimente}}",
+       "wikibase-snakview-property-input-placeholder": "proprietà",
        "wikibase-entityselector-more": "cchiù",
        "wikibase-wikibaserepopage-unresolved-redirect": "$1 è nu redirect.",
        "wikibase-itembytitle-lookup-site": "Sito:",
@@ -56,6 +60,7 @@
        "wikibase-dispatchstats-site-id": "Sito",
        "wikibase-dispatchstats-pos": "Pusizzione",
        "wikibase-dispatchstats-average": "Medio",
+       "wikibase-history-title-with-label": "Cronologgia d' 'e cagnamiente de 
\"$2\" ($1)",
        "wikibase-history-title-without-label": "Cronologgia d' 'e cagnamiente 
de ($1)",
        "wikibase-listproperties-submit": "Truòva",
        "wikibase-entitieswithoutlabel-label-language": "Codece lengua:",
@@ -64,8 +69,11 @@
        "wikibase-entitieswithoutlabel-submit": "Truòva",
        "wikibase-restoreold": "arrepiglia",
        "wikibase-listdatatypes-wikibase-item-head": "Oggietto",
+       "wikibase-listdatatypes-wikibase-property-head": "Proprietà",
        "wikibase-listdatatypes-string-head": "Stringa",
        "wikibase-listdatatypes-time-head": "Tiempo",
        "wikibase-listdatatypes-url-head": "URL",
-       "datatypes-type-url": "URL"
+       "datatypes-type-url": "URL",
+       "content-model-wikibase-item": "Oggietto Wikibase",
+       "content-model-wikibase-property": "Proprietà Wikibase"
 }
diff --git a/extensions/Wikibase/repo/i18n/olo.json 
b/extensions/Wikibase/repo/i18n/olo.json
index e33925f..9869e77 100644
--- a/extensions/Wikibase/repo/i18n/olo.json
+++ b/extensions/Wikibase/repo/i18n/olo.json
@@ -6,5 +6,5 @@
                ]
        },
        "wikibase-edit": "korjata",
-       "wikibase-add": "ližätä"
+       "wikibase-add": "ližiä"
 }
diff --git a/extensions/Wikibase/repo/i18n/vec.json 
b/extensions/Wikibase/repo/i18n/vec.json
index ab36f58..dbb0db5 100644
--- a/extensions/Wikibase/repo/i18n/vec.json
+++ b/extensions/Wikibase/repo/i18n/vec.json
@@ -59,6 +59,7 @@
        "wikibase-propertypage-datatype": "Tipo de dato",
        "wikibase-claimview-snak-tooltip": "Inserisi un valor corispondente a 
la proprietà che se ciama \"$1\". Se la proprietà no la ga nisun valor designà 
o se no se sa el valor efetivo, se pol sieliere n'alternativa a la specifica de 
un valor personalizà strucando su l'icona in parte a la casèla de input del 
valor.",
        "wikibase-claimview-snak-new-tooltip": "Dopo ver specificà na proprietà 
se pol inserir el valor corispondente. Se la proprietà no la ga nisun valor 
designà o se no se sa el valor efetivo, se pol sieliere n'alternativa a la 
specifica de un valor personalizà strucando su l'icona in parte a la casèla de 
input del valor.",
+       "wikibase-statementview-rank-normal": "Rango normal",
        "wikibase-statementview-referencesheading-pendingcountersubject": 
"{{PLURAL:$1|riferimento|riferimenti}}",
        "wikibase-statementview-referencesheading-pendingcountertooltip": 
"{{PLURAL:$1|Una fonte gnancora salvà|$1 fonti gnancora salvà}}",
        "wikibase-snakview-property-input-placeholder": "proprietà",
diff --git 
a/extensions/Wikibase/repo/includes/BuilderBasedDataTypeValidatorFactory.php 
b/extensions/Wikibase/repo/includes/BuilderBasedDataTypeValidatorFactory.php
index 047e04c..aa84d25 100644
--- a/extensions/Wikibase/repo/includes/BuilderBasedDataTypeValidatorFactory.php
+++ b/extensions/Wikibase/repo/includes/BuilderBasedDataTypeValidatorFactory.php
@@ -2,11 +2,12 @@
 
 namespace Wikibase\Repo;
 
+use OutOfBoundsException;
 use ValueValidators\ValueValidator;
 use Wikimedia\Assert\Assert;
 
 /**
- * A factory providing ValueValidators based on DataType id that uses 
ValidatorBuilders.
+ * A factory providing ValueValidators based on factory callbacks.
  *
  * @todo: unit tests!
  *
@@ -36,8 +37,8 @@
         */
        public function getValidators( $dataTypeId ) {
                if ( !isset( $this->validatorBuilders[ $dataTypeId ] ) ) {
-                       //@todo: test me!
-                       return array();
+                       // NOTE: fail hard, to avoid bypassing validators if 
the data type is mistyped or some such.
+                       throw new OutOfBoundsException( 'No validators known 
for data type ' . $dataTypeId );
                }
 
                $validators = call_user_func(
diff --git a/extensions/Wikibase/repo/includes/ValidatorBuilders.php 
b/extensions/Wikibase/repo/includes/ValidatorBuilders.php
index 550122d..03a4b7f 100644
--- a/extensions/Wikibase/repo/includes/ValidatorBuilders.php
+++ b/extensions/Wikibase/repo/includes/ValidatorBuilders.php
@@ -24,7 +24,10 @@
 use Wikibase\Repo\Validators\UrlValidator;
 
 /**
- * Defines validators for the data types supported by Wikibase.
+ * Defines validators for the basic well known data types supported by 
Wikibase.
+ *
+ * @warning: This is a low level factory for use by boostrap code only!
+ * Program logic should use an instance of DataTypeValidatorFactory.
  *
  * @since 0.4
  *
@@ -70,34 +73,6 @@
                $this->entityIdParser = $idParser;
                $this->entityLookup = $lookup;
                $this->urlSchemes = $urlSchemes;
-       }
-
-       /**
-        * @return callable[] ValueValidator for DataTypes build spec
-        */
-       public function getDataTypeValidators() {
-
-               $types = array(
-                       'commonsMedia'      => array( $this, 
'buildMediaValidators' ),
-                       'globe-coordinate'  => array( $this, 
'buildCoordinateValidators' ),
-                       'monolingualtext'   => array( $this, 
'buildMonolingualTextValidators' ),
-                       'quantity'          => array( $this, 
'buildQuantityValidators' ),
-                       'string'            => array( $this, 
'buildStringValidators' ),
-                       'time'              => array( $this, 
'buildTimeValidators' ),
-                       'url'               => array( $this, 
'buildUrlValidators' ),
-                       'wikibase-item'     => array( $this, 
'buildItemValidators' ),
-                       'wikibase-property' => array( $this, 
'buildPropertyValidators' ),
-               );
-
-               $experimental = array(
-                       // 'multilingualtext' => array( $this, 
'buildMultilingualTextValidators' ),
-               );
-
-               if ( defined( 'WB_EXPERIMENTAL_FEATURES' ) && 
WB_EXPERIMENTAL_FEATURES ) {
-                       $types = array_merge( $types, $experimental );
-               }
-
-               return $types;
        }
 
        /**
diff --git a/extensions/Wikibase/repo/includes/ValueParserFactory.php 
b/extensions/Wikibase/repo/includes/ValueParserFactory.php
index a54acc3..8c46540 100644
--- a/extensions/Wikibase/repo/includes/ValueParserFactory.php
+++ b/extensions/Wikibase/repo/includes/ValueParserFactory.php
@@ -20,17 +20,17 @@
        /**
         * Maps parser id to ValueParser class or builder callback.
         *
-        * @since 0.1
+        * @since 0.5
         *
-        * @var array
+        * @var callable[]
         */
        protected $parsers = array();
 
        /**
-        * @since 0.1
+        * @since 0.5
         *
-        * @param string|callable[] $valueParsers An associative array mapping 
parser ids to
-        *        class names or callable builders.
+        * @param callable[] $valueParsers An associative array mapping parser 
ids to
+        *        factory functions.
         *
         * @throws InvalidArgumentException
         */
@@ -40,8 +40,8 @@
                                throw new InvalidArgumentException( 'Parser id 
needs to be a string' );
                        }
 
-                       if ( !is_string( $parserBuilder ) && !is_callable( 
$parserBuilder ) ) {
-                               throw new InvalidArgumentException( 'Parser 
class needs to be a class name or callable' );
+                       if ( !is_callable( $parserBuilder ) ) {
+                               throw new InvalidArgumentException( 'Parser 
class needs to be a callable' );
                        }
 
                        $this->parsers[$parserId] = $parserBuilder;
@@ -57,24 +57,6 @@
         */
        public function getParserIds() {
                return array_keys( $this->parsers );
-       }
-
-       /**
-        * Returns the parser builder (class name or callable) for $parserId, 
or null if
-        * no builder was registered for that id.
-        *
-        * @since 0.1
-        *
-        * @param string $parserId
-        *
-        * @return string|callable|null
-        */
-       public function getParserBuilder( $parserId ) {
-               if ( array_key_exists( $parserId, $this->parsers ) ) {
-                       return $this->parsers[$parserId];
-               }
-
-               return null;
        }
 
        /**
@@ -100,20 +82,15 @@
        }
 
        /**
-        * @param string|callable $builder Either a classname of an 
implementation of ValueParser,
-        *        or a callable that returns a ValueParser. $options will be 
passed to the constructor
-        *        or callable, respectively.
+        * @param callable $builder A callable that returns a ValueParser.
+        *        $options will be passed to the constructor or callable, 
respectively.
         * @param ParserOptions $options
         *
         * @throws LogicException if the builder did not create a ValueParser
         * @return ValueParser
         */
        private function instantiateParser( $builder, ParserOptions $options ) {
-               if ( is_string( $builder ) ) {
-                       $parser = new $builder( $options );
-               } else {
-                       $parser = call_user_func( $builder, $options );
-               }
+               $parser = call_user_func( $builder, $options );
 
                if ( !( $parser instanceof ValueParser ) ) {
                        throw new LogicException( "Invalid parser builder, did 
not create an instance of ValueParser." );
diff --git a/extensions/Wikibase/repo/includes/WikibaseRepo.php 
b/extensions/Wikibase/repo/includes/WikibaseRepo.php
index d1ce6b0..a844700 100644
--- a/extensions/Wikibase/repo/includes/WikibaseRepo.php
+++ b/extensions/Wikibase/repo/includes/WikibaseRepo.php
@@ -16,6 +16,7 @@
 use User;
 use ValueFormatters\FormatterOptions;
 use ValueFormatters\ValueFormatter;
+use Wikibase\Lib\DataTypeDefinitions;
 use Wikibase\ChangeOp\ChangeOpFactoryProvider;
 use Wikibase\DataModel\DeserializerFactory;
 use Wikibase\DataModel\Entity\Item;
@@ -119,6 +120,11 @@
        private $dataTypeFactory = null;
 
        /**
+        * @var ValueParserFactory|null
+        */
+       private $valueParserFactory = null;
+
+       /**
         * @var SnakConstructionService|null
         */
        private $snakConstructionService = null;
@@ -194,6 +200,11 @@
        private $monolingualTextLanguages = null;
 
        /**
+        * @var DataTypeDefinitions
+        */
+       private $dataTypeDefinitions;
+
+       /**
         * Returns the default instance constructed using newInstance().
         * IMPORTANT: Use only when it is not feasible to inject an instance 
properly.
         *
@@ -202,22 +213,74 @@
         * @return WikibaseRepo
         */
        public static function getDefaultInstance() {
+               global $wgWBRepoDataTypes, $wgWBRepoSettings;
                static $instance = null;
 
+               $dataTypeDefinitions = $wgWBRepoDataTypes;
+               Hooks::run( 'WikibaseRepoDataTypes', array( 
&$dataTypeDefinitions ) );
+
                if ( $instance === null ) {
-                       $instance = new self( new SettingsArray( 
$GLOBALS['wgWBRepoSettings'] ) );
+                       $instance = new self(
+                               new SettingsArray( $wgWBRepoSettings ),
+                               new DataTypeDefinitions( $dataTypeDefinitions )
+                       );
                }
 
                return $instance;
        }
 
        /**
+        * Returns the default ValidatorBuilders instance.
+        * @warning This is for use with bootstrap code in 
WikibaseRepo.datatypes.php only!
+        * Program logic should use WikibaseRepo::getDataTypeValidatorFactory() 
instead!
+        *
+        * @since 0.5
+        *
+        * @param string $reset Flag: Pass "reset" to reset the default instance
+        *
+        * @return ValidatorBuilders
+        */
+       public static function getDefaultValidatorBuilders( $reset = 'noreset' 
) {
+               static $builders;
+
+               if ( $builders === null || $reset === 'reset' ) {
+                       $wikibaseRepo = self::getDefaultInstance();
+                       $builders = $wikibaseRepo->newValidatorBuilders();
+               }
+
+               return $builders;
+       }
+
+       /**
+        * Returns a low level factory object for creating validators for well 
known data types.
+        * @warning This is for use with getDefaultValidatorBuilders() during 
bootstrap only!
+        * Program logic should use WikibaseRepo::getDataTypeValidatorFactory() 
instead!
+        *
+        * @return ValidatorBuilders
+        */
+       private function newValidatorBuilders() {
+               $urlSchemes = $this->settings->getSetting( 'urlSchemes' );
+
+               return new ValidatorBuilders(
+                       $this->getEntityLookup(),
+                       $this->getEntityIdParser(),
+                       $urlSchemes,
+                       $this->getMonolingualTextLanguages()
+               );
+       }
+
+       /**
         * @since 0.4
         *
         * @param SettingsArray $settings
+        * @param DataTypeDefinitions $dataTypeDefinitions
         */
-       public function __construct( SettingsArray $settings ) {
+       public function __construct(
+               SettingsArray $settings,
+               DataTypeDefinitions $dataTypeDefinitions
+       ) {
                $this->settings = $settings;
+               $this->dataTypeDefinitions = $dataTypeDefinitions;
        }
 
        /**
@@ -227,24 +290,30 @@
         */
        public function getDataTypeFactory() {
                if ( $this->dataTypeFactory === null ) {
-                       // Temporary hack, will be removed in a follow-up
-                       $types = array(
-                               'commonsMedia'      => 'string',
-                               'globe-coordinate'  => 'globecoordinate',
-                               'monolingualtext'   => 'monolingualtext',
-                               'multilingualtext'  => 'multilingualtext',
-                               'quantity'          => 'quantity',
-                               'string'            => 'string',
-                               'time'              => 'time',
-                               'url'               => 'string',
-                               'wikibase-item'     => 'wikibase-entityid',
-                               'wikibase-property' => 'wikibase-entityid',
-                       );
-
-                       $this->dataTypeFactory = new DataTypeFactory( $types );
+                       $this->dataTypeFactory = new DataTypeFactory( 
$this->dataTypeDefinitions->getValueTypes() );
                }
 
                return $this->dataTypeFactory;
+       }
+
+       /**
+        * @since 0.5
+        *
+        * @return ValueParserFactory
+        */
+       public function getValueParserFactory() {
+               global $wgValueParsers;
+
+               if ( $this->valueParserFactory === null ) {
+                       $callbacks = 
$this->dataTypeDefinitions->getParserFactoryCallbacks();
+
+                       // For backwards-compatibility, also register parsers 
under legacy names.
+                       $callbacks = array_merge( $wgValueParsers, $callbacks );
+
+                       $this->valueParserFactory = new ValueParserFactory( 
$callbacks );
+               }
+
+               return $this->valueParserFactory;
        }
 
        /**
@@ -1199,18 +1268,13 @@
                );
        }
 
+       /**
+        * @return DataTypeValidatorFactory
+        */
        public function getDataTypeValidatorFactory() {
-               $urlSchemes = $this->settings->getSetting( 'urlSchemes' );
-
-               $builders = new ValidatorBuilders(
-                       $this->getEntityLookup(),
-                       $this->getEntityIdParser(),
-                       $urlSchemes,
-                       $this->getMonolingualTextLanguages()
-               );
 
                return new BuilderBasedDataTypeValidatorFactory(
-                       $builders->getDataTypeValidators()
+                       
$this->dataTypeDefinitions->getValidatorFactoryCallbacks()
                );
        }
 
diff --git a/extensions/Wikibase/repo/includes/api/ParseValue.php 
b/extensions/Wikibase/repo/includes/api/ParseValue.php
index 1321e4d..29b83ff 100644
--- a/extensions/Wikibase/repo/includes/api/ParseValue.php
+++ b/extensions/Wikibase/repo/includes/api/ParseValue.php
@@ -81,7 +81,7 @@
 
                $this->setServices(
                        $wikibaseRepo->getDataTypeFactory(),
-                       new ValueParserFactory( $GLOBALS['wgValueParsers'] ),
+                       $wikibaseRepo->getValueParserFactory(),
                        $wikibaseRepo->getDataTypeValidatorFactory(),
                        $wikibaseRepo->getExceptionLocalizer(),
                        $wikibaseRepo->getValidatorErrorLocalizer(),
@@ -135,9 +135,9 @@
                $options = $this->getOptionsObject( $params['options'] );
 
                // Parsers are registered by datatype.
-               // Note: parser used to be addressed by a name independant of 
datatype, using the 'parser'
+               // Note: parser used to be addressed by a name independent of 
datatype, using the 'parser'
                // parameter. For backwards compatibility, parsers are also 
registered under their old names
-               // in $wgValueParsers, and this in the ValueParserFactory.
+               // in $wgValueParsers, and thus in the ValueParserFactory.
                $name = $params['datatype'] ?: $params['parser'];
 
                if ( empty( $name ) ) {
diff --git a/extensions/Wikibase/repo/includes/specials/SpecialItemByTitle.php 
b/extensions/Wikibase/repo/includes/specials/SpecialItemByTitle.php
index 8aeab61..23289ea 100644
--- a/extensions/Wikibase/repo/includes/specials/SpecialItemByTitle.php
+++ b/extensions/Wikibase/repo/includes/specials/SpecialItemByTitle.php
@@ -227,7 +227,7 @@
                                )
                        )
                        . Html::input(
-                               'submit',
+                               '',
                                $this->msg( 'wikibase-itembytitle-submit' 
)->text(),
                                'submit',
                                array(
diff --git 
a/extensions/Wikibase/repo/includes/specials/SpecialItemDisambiguation.php 
b/extensions/Wikibase/repo/includes/specials/SpecialItemDisambiguation.php
index dca4a8a..2d6aaab 100644
--- a/extensions/Wikibase/repo/includes/specials/SpecialItemDisambiguation.php
+++ b/extensions/Wikibase/repo/includes/specials/SpecialItemDisambiguation.php
@@ -2,6 +2,7 @@
 
 namespace Wikibase\Repo\Specials;
 
+use HTMLForm;
 use Html;
 use Language;
 use Wikibase\ItemDisambiguation;
@@ -192,71 +193,47 @@
        private function switchForm( $languageCode, $label ) {
                $this->getOutput()->addModules( 
'wikibase.special.languageSuggester' );
 
-               $this->getOutput()->addHTML(
-                       Html::openElement(
-                               'form',
-                               array(
-                                       'method' => 'get',
-                                       'action' => 
$this->getPageTitle()->getFullUrl(),
-                                       'name' => 'itemdisambiguation',
-                                       'id' => 'wb-itemdisambiguation-form1'
-                               )
+               $formDescriptor = array(
+                       'language' => array(
+                               'name' => 'language',
+                               'default' => $languageCode ?: '',
+                               'type' => 'text',
+                               'id' => 'wb-itemdisambiguation-languagename',
+                               'size' => 12,
+                               'cssclass' => 'wb-input-text 
wb-language-suggester',
+                               'label-message' => 
'wikibase-itemdisambiguation-lookup-language'
+                       ),
+                       'label' => array(
+                               'name' => 'label',
+                               'default' => $label ?: '',
+                               'type' => 'text',
+                               'id' => 'labelname',
+                               'size' => 36,
+                               'cssclass' => 'wb-input-text',
+                               'autofocus',
+                               'label-message' => 
'wikibase-itemdisambiguation-lookup-label'
+                       ),
+                       'submit' => array(
+                               'name' => 'submit',
+                               'default' => $this->msg( 
'wikibase-itemdisambiguation-submit' )->text(),
+                               'type' => 'submit',
+                               'id' => 'wb-itembytitle-submit',
+                               'cssclass' => 'wb-input-button'
                        )
-                       . Html::openElement( 'fieldset' )
-                       . Html::element(
-                               'legend',
-                               array(),
-                               $this->msg( 
'wikibase-itemdisambiguation-lookup-fieldset' )->text()
-                       )
-                       . Html::element(
-                               'label',
-                               array( 'for' => 
'wb-itemdisambiguation-languagename' ),
-                               $this->msg( 
'wikibase-itemdisambiguation-lookup-language' )->text()
-                       )
-                       . Html::input(
-                               'language',
-                               $languageCode ?: '',
-                               'text',
-                               array(
-                                       'id' => 
'wb-itemdisambiguation-languagename',
-                                       'size' => 12,
-                                       'class' => 'wb-input-text 
wb-language-suggester'
-                               )
-                       )
-                       . ' '
-                       . Html::element(
-                               'label',
-                               array( 'for' => 'labelname' ),
-                               $this->msg( 
'wikibase-itemdisambiguation-lookup-label' )->text()
-                       )
-                       . Html::input(
-                               'label',
-                               $label ?: '',
-                               'text',
-                               array(
-                                       'id' => 'labelname',
-                                       'size' => 36,
-                                       'class' => 'wb-input-text',
-                                       'autofocus'
-                               )
-                       )
-                       . Html::input(
-                               'submit',
-                               $this->msg( 
'wikibase-itemdisambiguation-submit' )->text(),
-                               'submit',
-                               array(
-                                       'id' => 'wb-itembytitle-submit',
-                                       'class' => 'wb-input-button'
-                               )
-                       )
-                       . Html::element(
+               );
+
+               HTMLForm::factory( 'inline', $formDescriptor, 
$this->getContext() )
+                       ->setId( 'wb-itemdisambiguation-form1' )
+                       ->setMethod( 'get' )
+                       ->setFooterText( Html::element(
                                'p',
                                array(),
                                $this->msg( 
'wikibase-itemdisambiguation-form-hints' )->numParams( $this->limit )->text()
-                       )
-                       . Html::closeElement( 'fieldset' )
-                       . Html::closeElement( 'form' )
-               );
+                       ) )
+                       ->setWrapperLegendMsg( 
'wikibase-itemdisambiguation-lookup-fieldset' )
+                       ->suppressDefaultSubmit()
+                       ->setSubmitCallback( function () {// no-op
+                       } )->show();
        }
 
 }
diff --git 
a/extensions/Wikibase/repo/tests/phpunit/includes/ValidatorBuildersTest.php 
b/extensions/Wikibase/repo/tests/phpunit/includes/ValidatorBuildersTest.php
index 26b9380..669d888 100644
--- a/extensions/Wikibase/repo/tests/phpunit/includes/ValidatorBuildersTest.php
+++ b/extensions/Wikibase/repo/tests/phpunit/includes/ValidatorBuildersTest.php
@@ -31,7 +31,7 @@
  */
 class ValidatorBuildersTest extends PHPUnit_Framework_TestCase {
 
-       protected function newValidatorFactory() {
+       protected function newValidatorBuilders() {
                $entityIdParser = new BasicEntityIdParser();
 
                $q8 = new Item( new ItemId( 'Q8' ) );
@@ -56,9 +56,8 @@
                        $urlSchemes,
                        $contentLanguages
                );
-               $validatorFactory = new BuilderBasedDataTypeValidatorFactory( 
$builders->getDataTypeValidators() );
 
-               return $validatorFactory;
+               return $builders;
        }
 
        public function provideDataTypeValidation() {
@@ -246,8 +245,21 @@
         * @dataProvider provideDataTypeValidation
         */
        public function testDataTypeValidation( $typeId, $value, $expected, 
$message ) {
-               $validatorsFactory = $this->newValidatorFactory();
-               $validators = $validatorsFactory->getValidators( $typeId );
+               $builders = $this->newValidatorBuilders();
+
+               $validatorMap = array(
+                       'commonsMedia'      => array( $builders, 
'buildMediaValidators' ),
+                       'globe-coordinate'  => array( $builders, 
'buildCoordinateValidators' ),
+                       'monolingualtext'   => array( $builders, 
'buildMonolingualTextValidators' ),
+                       'quantity'          => array( $builders, 
'buildQuantityValidators' ),
+                       'string'            => array( $builders, 
'buildStringValidators' ),
+                       'time'              => array( $builders, 
'buildTimeValidators' ),
+                       'url'               => array( $builders, 
'buildUrlValidators' ),
+                       'wikibase-item'     => array( $builders, 
'buildItemValidators' ),
+                       'wikibase-property' => array( $builders, 
'buildPropertyValidators' ),
+               );
+
+               $validators = call_user_func( $validatorMap[$typeId] );
 
                $this->assertValidation( $expected, $validators, $value, 
$message );
        }
diff --git 
a/extensions/Wikibase/repo/tests/phpunit/includes/ValueParserFactoryTest.php 
b/extensions/Wikibase/repo/tests/phpunit/includes/ValueParserFactoryTest.php
index 261fc1f..937480e 100644
--- a/extensions/Wikibase/repo/tests/phpunit/includes/ValueParserFactoryTest.php
+++ b/extensions/Wikibase/repo/tests/phpunit/includes/ValueParserFactoryTest.php
@@ -2,6 +2,8 @@
 
 namespace Wikibase\Tests\Repo;
 
+use ValueParsers\NullParser;
+use ValueParsers\ParserOptions;
 use Wikibase\Repo\ValueParserFactory;
 
 /**
@@ -14,26 +16,42 @@
  * @licence GNU GPL v2+
  * @author Adrian Lang <[email protected]>
  */
-class ValueParserFactoryTest extends \MediaWikiTestCase {
+class ValueParserFactoryTest extends \PHPUnit_Framework_TestCase {
 
        /**
-        * @dataProvider getParserIdsProvider
+        * @dataProvider provideFactoryFunctions
         */
-       public function testGetParserIds( $valueParsers, $expected ) {
-               $valueParserFactory = new ValueParserFactory( $valueParsers );
+       public function testGetParserIds( $factoryFunctions ) {
+               $valueParserFactory = new ValueParserFactory( $factoryFunctions 
);
 
                $returnValue = $valueParserFactory->getParserIds();
 
-               $this->assertEquals( $expected, $returnValue );
+               $this->assertEquals( array_keys( $factoryFunctions ), 
$returnValue );
        }
 
-       public function getParserIdsProvider() {
+       public function provideFactoryFunctions() {
                return array(
                        array(
-                               array( 'key' => 'value' ),
-                               array( 'key' )
+                               array(
+                                       'foo' => function() {
+                                               return new NullParser();
+                                       }
+                               ),
                        )
                );
        }
 
+       /**
+        * @dataProvider provideFactoryFunctions
+        */
+       public function testNewParser( $factoryFunctions ) {
+               $valueParserFactory = new ValueParserFactory( $factoryFunctions 
);
+               $options = new ParserOptions();
+
+               foreach ( $valueParserFactory->getParserIds() as $id ) {
+                       $parser = $valueParserFactory->newParser( $id, $options 
);
+                       $this->assertInstanceOf( 'ValueParsers\ValueParser', 
$parser );
+               }
+       }
+
 }
diff --git 
a/extensions/Wikibase/repo/tests/phpunit/includes/WikibaseRepoTest.php 
b/extensions/Wikibase/repo/tests/phpunit/includes/WikibaseRepoTest.php
index 8b67403..d28e05d 100644
--- a/extensions/Wikibase/repo/tests/phpunit/includes/WikibaseRepoTest.php
+++ b/extensions/Wikibase/repo/tests/phpunit/includes/WikibaseRepoTest.php
@@ -2,6 +2,7 @@
 
 namespace Wikibase\Tests\Repo;
 
+use Wikibase\Lib\DataTypeDefinitions;
 use Wikibase\Repo\WikibaseRepo;
 use Wikibase\SettingsArray;
 
@@ -22,6 +23,11 @@
        public function testGetDataTypeFactoryReturnType() {
                $returnValue = $this->getWikibaseRepo()->getDataTypeFactory();
                $this->assertInstanceOf( 'DataTypes\DataTypeFactory', 
$returnValue );
+       }
+
+       public function testGetValueParserFactoryReturnType() {
+               $returnValue = 
$this->getWikibaseRepo()->getValueParserFactory();
+               $this->assertInstanceOf( 'Wikibase\Repo\ValueParserFactory', 
$returnValue );
        }
 
        public function testGetDataValueFactoryReturnType() {
@@ -214,7 +220,7 @@
         */
        private function getWikibaseRepo() {
                $settings = new SettingsArray( 
WikibaseRepo::getDefaultInstance()->getSettings()->getArrayCopy() );
-               return new WikibaseRepo( $settings );
+               return new WikibaseRepo( $settings, new DataTypeDefinitions() );
        }
 
        public function testGetApiHelperFactory() {
diff --git 
a/extensions/Wikibase/repo/tests/phpunit/includes/api/ParseValueTest.php 
b/extensions/Wikibase/repo/tests/phpunit/includes/api/ParseValueTest.php
index 13356b1..734394b 100644
--- a/extensions/Wikibase/repo/tests/phpunit/includes/api/ParseValueTest.php
+++ b/extensions/Wikibase/repo/tests/phpunit/includes/api/ParseValueTest.php
@@ -3,8 +3,8 @@
 namespace Wikibase\Test\Repo\Api;
 
 use ApiMain;
-use DataTypes\DataType;
 use DataTypes\DataTypeFactory;
+use DataValues\Geo\Parsers\GlobeCoordinateParser;
 use FauxRequest;
 use Language;
 use ValueParsers\NullParser;
@@ -60,7 +60,7 @@
                        'null' => array( $this, 'newNullParser' ),
                        'string' => array( $this, 'newNullParser' ),
                        'url' => array( $this, 'newNullParser' ),
-                       'globe-coordinate' => 
'DataValues\Geo\Parsers\GlobeCoordinateParser',
+                       'globe-coordinate' => array( $this, 
'newGlobeCoordinateParser' ),
                ) );
 
                $validatorFactory = new BuilderBasedDataTypeValidatorFactory( 
array(
@@ -91,6 +91,10 @@
                return new NullParser();
        }
 
+       public function newGlobeCoordinateParser() {
+               return new GlobeCoordinateParser();
+       }
+
        private function callApiModule( array $params ) {
                $module = $this->newApiModule( $params );
 
diff --git 
a/extensions/Wikibase/repo/tests/phpunit/includes/content/EntityHandlerTest.php 
b/extensions/Wikibase/repo/tests/phpunit/includes/content/EntityHandlerTest.php
index 1a8af78..55c4b78 100644
--- 
a/extensions/Wikibase/repo/tests/phpunit/includes/content/EntityHandlerTest.php
+++ 
b/extensions/Wikibase/repo/tests/phpunit/includes/content/EntityHandlerTest.php
@@ -13,6 +13,8 @@
 use Wikibase\DataModel\Entity\EntityId;
 use Wikibase\EntityContent;
 use Wikibase\InternalSerialization\SerializerFactory;
+use Wikibase\Lib\DataTypeDefinitions;
+use Wikibase\Lib\Serializers\LegacyInternalEntitySerializer;
 use Wikibase\Lib\Store\EntityRedirect;
 use Wikibase\Repo\Content\EntityHandler;
 use Wikibase\Repo\WikibaseRepo;
@@ -58,7 +60,7 @@
                        $repoSettings = array_merge( $repoSettings, 
$settings->getArrayCopy() );
                }
 
-               return new WikibaseRepo( new SettingsArray( $repoSettings ) );
+               return new WikibaseRepo( new SettingsArray( $repoSettings ), 
new DataTypeDefinitions() );
        }
 
        /**
diff --git 
a/extensions/Wikibase/repo/tests/phpunit/includes/specials/SpecialItemByTitleTest.php
 
b/extensions/Wikibase/repo/tests/phpunit/includes/specials/SpecialItemByTitleTest.php
index cb3816f..34eec76 100644
--- 
a/extensions/Wikibase/repo/tests/phpunit/includes/specials/SpecialItemByTitleTest.php
+++ 
b/extensions/Wikibase/repo/tests/phpunit/includes/specials/SpecialItemByTitleTest.php
@@ -130,7 +130,7 @@
                                'id' => 'wb-itembytitle-submit',
                                'class' => 'wb-button',
                                'type' => 'submit',
-                               'name' => 'submit',
+                               'name' => '',
                        ) );
 
                $cases['empty'] = array( '', null, $matchers );
diff --git a/vendor/composer/autoload_classmap.php 
b/vendor/composer/autoload_classmap.php
index 66152c3..65be711 100644
--- a/vendor/composer/autoload_classmap.php
+++ b/vendor/composer/autoload_classmap.php
@@ -655,6 +655,7 @@
     'Wikibase\\Lib\\Changes\\EntityChangeFactory' => $baseDir . 
'/extensions/Wikibase/lib/includes/changes/EntityChangeFactory.php',
     'Wikibase\\Lib\\CommonsLinkFormatter' => $baseDir . 
'/extensions/Wikibase/lib/includes/formatters/CommonsLinkFormatter.php',
     'Wikibase\\Lib\\ContentLanguages' => $baseDir . 
'/extensions/Wikibase/lib/includes/ContentLanguages.php',
+    'Wikibase\\Lib\\DataTypeDefinitions' => $baseDir . 
'/extensions/Wikibase/lib/includes/DataTypeDefinitions.php',
     'Wikibase\\Lib\\DispatchingSnakFormatter' => $baseDir . 
'/extensions/Wikibase/lib/includes/formatters/DispatchingSnakFormatter.php',
     'Wikibase\\Lib\\DispatchingValueFormatter' => $baseDir . 
'/extensions/Wikibase/lib/includes/formatters/DispatchingValueFormatter.php',
     'Wikibase\\Lib\\EntityIdHtmlLinkFormatter' => $baseDir . 
'/extensions/Wikibase/lib/includes/formatters/EntityIdHtmlLinkFormatter.php',
@@ -772,6 +773,7 @@
     'Wikibase\\Lib\\Test\\WikibaseSnakFormatterBuildersTest' => $baseDir . 
'/extensions/Wikibase/lib/tests/phpunit/formatters/WikibaseSnakFormatterBuildersTest.php',
     'Wikibase\\Lib\\Test\\WikibaseStringValueNormalizerTest' => $baseDir . 
'/extensions/Wikibase/lib/tests/phpunit/parsers/WikibaseStringValueNormalizerTest.php',
     'Wikibase\\Lib\\Test\\WikibaseValueFormatterBuildersTest' => $baseDir . 
'/extensions/Wikibase/lib/tests/phpunit/formatters/WikibaseValueFormatterBuildersTest.php',
+    'Wikibase\\Lib\\Tests\\DataTypeDefinitionsTest' => $baseDir . 
'/extensions/Wikibase/lib/tests/phpunit/DataTypeDefinitionsTest.php',
     'Wikibase\\Lib\\Tests\\Parsers\\TimeParserFactoryTest' => $baseDir . 
'/extensions/Wikibase/lib/tests/phpunit/parsers/TimeParserFactoryTest.php',
     'Wikibase\\Lib\\TimeDetailsFormatter' => $baseDir . 
'/extensions/Wikibase/lib/includes/formatters/TimeDetailsFormatter.php',
     'Wikibase\\Lib\\TypedValueFormatter' => $baseDir . 
'/extensions/Wikibase/lib/includes/TypedValueFormatter.php',
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 278ef28..cce2719 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -1279,12 +1279,12 @@
         "source": {
             "type": "git",
             "url": 
"https://github.com/wikimedia/mediawiki-extensions-Wikibase.git";,
-            "reference": "c3a5e05eae970c8d19091ad6d5a535fed4276a6d"
+            "reference": "2a25cd4e403874e843591a0abf7ad5636b098894"
         },
         "dist": {
             "type": "zip",
-            "url": 
"https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/c3a5e05eae970c8d19091ad6d5a535fed4276a6d";,
-            "reference": "c3a5e05eae970c8d19091ad6d5a535fed4276a6d",
+            "url": 
"https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/2a25cd4e403874e843591a0abf7ad5636b098894";,
+            "reference": "2a25cd4e403874e843591a0abf7ad5636b098894",
             "shasum": ""
         },
         "require": {
@@ -1315,7 +1315,7 @@
         "require-dev": {
             "squizlabs/php_codesniffer": "~2.1"
         },
-        "time": "2015-09-01 09:30:08",
+        "time": "2015-09-02 02:58:03",
         "type": "mediawiki-extension",
         "installation-source": "dist",
         "autoload": {
@@ -1448,7 +1448,7 @@
         "source": {
             "type": "git",
             "url": 
"https://gerrit.wikimedia.org/r/mediawiki/extensions/WikibaseQuality";,
-            "reference": "619c61d0cbf0f8c36804f820dc0570581eb0d42d"
+            "reference": "ae47f3e1baa725fef1c14825738a1510e733210b"
         },
         "require": {
             "php": ">=5.3.0",
@@ -1460,7 +1460,7 @@
             "phpunit/phpunit": "^3.7.37|~4.5",
             "satooshi/php-coveralls": "master-dev"
         },
-        "time": "2015-08-29 19:48:01",
+        "time": "2015-09-01 19:46:52",
         "type": "mediawiki-extension",
         "installation-source": "source",
         "autoload": {
@@ -1502,7 +1502,7 @@
         "source": {
             "type": "git",
             "url": 
"https://gerrit.wikimedia.org/r/mediawiki/extensions/WikibaseQualityConstraints";,
-            "reference": "d0e7eab7eb73920009e496cf3a2d9b9dfbf8be16"
+            "reference": "82a02aae853d042aa8293aabf29767580baba94c"
         },
         "require": {
             "php": ">=5.3.0",
@@ -1514,7 +1514,7 @@
             "phpunit/phpunit": "^3.7.37|~4.5",
             "satooshi/php-coveralls": "master-dev"
         },
-        "time": "2015-08-27 19:40:22",
+        "time": "2015-09-01 19:46:56",
         "type": "mediawiki-extension",
         "installation-source": "source",
         "autoload": {

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I7b0d2f67988c9ab17c186c024cfee1954e48489b
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikidata
Gerrit-Branch: master
Gerrit-Owner: WikidataBuilder <[email protected]>
Gerrit-Reviewer: Addshore <[email protected]>
Gerrit-Reviewer: Aude <[email protected]>
Gerrit-Reviewer: JanZerebecki <[email protected]>
Gerrit-Reviewer: Siebrand <[email protected]>
Gerrit-Reviewer: Tobias Gritschacher <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

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

Reply via email to