r20722 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r20721‎ | r20722 | r20723 >
Date:23:23, 26 March 2007
Author:daniel
Status:old
Tags:
Comment:
new extension implementing automatic redirects to localized pages based on user language
Modified paths:
  • /trunk/extensions/Polyglot (added) (history)
  • /trunk/extensions/Polyglot/Polyglot.php (added) (history)
  • /trunk/extensions/Polyglot/README (added) (history)
  • /trunk/extensions/Polyglot/install.settings (added) (history)

Diff [purge]

Index: trunk/extensions/Polyglot/README
@@ -0,0 +1,84 @@
 2+--------------------------------------------------------------------------
 3+README for the Polyglot extension
 4+Copyright © 2007 Daniel Kinzler
 5+Licenses: GNU General Public Licence (GPL)
 6+ GNU Free Documentation License (GFDL)
 7+--------------------------------------------------------------------------
 8+
 9+Polyglot is EXPERIMENTAL
 10+
 11+The Polyglot extension provides automatic redirects based on user language.
 12+This allows for multilingual content to be handeled more easily on a
 13+single wiki. Polyglot also changes the interlanguage links in the sidebar
 14+to automatically show available localized version of each page.
 15+
 16+For more comprehensive support for multilingual content, Polyglot can be
 17+combined with the MultiLang and LanguageSelector extensions.
 18+
 19+Automatic redirects are performed based on a naming scheme: when visiting
 20+the page Foo with the user language set to de (German), Polyglot would
 21+redirect the user to Foo/de, if it exists. This automatic redirection can
 22+be bypassed by visiting Foo/, which will always show Foo proper. The base
 23+page (Foo in this example) is considered to be associated with the wiki's
 24+content language ($wgLanguageCode in LocalSettings.php).
 25+
 26+Note that Polyglot can not readily be used to localized templates. Instead,
 27+use the Multilang extension for template messages.
 28+
 29+The Polyglot extension was originally written by Daniel Kinzler in 2007
 30+and is released under the GNU General Public Licence (GPL).
 31+
 32+<http://mediawiki.org/wiki/Extension:Polyglot>
 33+
 34+== Installing ==
 35+
 36+Copy the Polyglot directory into the extensions folder of your
 37+MediaWiki installation. Then add the following line to your
 38+LocalSettings.php file (near the end):
 39+
 40+ require_once( "$IP/extensions/Polyglot/Polyglot.php" );
 41+
 42+== Configuration ==
 43+
 44+You can specify the following settings in your LocalSettings.php (after
 45+including the extension file):
 46+
 47+* $wgPolyglotLanguages: Languages to be considered when looking for
 48+ matching subpages (localized versions). If set th NULL (the default),
 49+ all languages known to MediaWiki (by $wgLanguageNames) are considered.
 50+ If the LanguageSelector extension is installed and
 51+ $wgLanguageSelectorLanguages is set, that value will be used as a fallback.
 52+ Setting $wgPolyglotLanguages to a shorter list may speed things up,
 53+ especially on large wikis.
 54+
 55+* $wfPolyglotExcemptNamespaces: namespaces that should not have magic
 56+ redirection applied by Polyglot. Per default, this includes the
 57+ Category, Image, Template, MediaWiki, Media, and Special namespaces.
 58+ There should be no reason to remove any of those, but you can add more
 59+ namespaces to be left alone.
 60+
 61+* $wfPolyglotExcemptTalkPages: wether talk pages should be imune to magic
 62+ redirection by Polyglot. true per default.
 63+
 64+* $wfPolyglotFollowRedirects: wether Polyglot should follow redirects it find
 65+ as the target of a magic redirect. This is false per default; setting it to
 66+ true causes an additional database lookup on every magic redirect, but it
 67+ allows for locaized page titles. For example, Main_Page/de could redirect to
 68+ Hauptseite, so people with the user language set to "de" (German) would end
 69+ up on a page called "Hauptseite" instead of the clunky "Main_Page/de".
 70+ NOTE: currently, the magic interlanguage links don't take into consideration
 71+ this type of redirect.
 72+
 73+== Todo ==
 74+* allowing users to define page localization links manually, using the standard
 75+ interlanguage link syntax and mechanism. Which links are treated as
 76+ interlanguage links is determiend by the interwiki table. An additional hook
 77+ in Title.php would be needed to solved that. Or dummy entries in the
 78+ interwiki table.
 79+
 80+* When following redirects ( base -> local -> target ), make the "redirected
 81+ from" bit show both, the base and the refering page. Would require a skin
 82+ hack.
 83+
 84+* When following redirects, look at the redirecting pages subpages and
 85+ siblings, and merge the result with the target page's language links.
Index: trunk/extensions/Polyglot/Polyglot.php
@@ -0,0 +1,269 @@
 2+<?php
 3+/**
 4+ * Polyglot extension - automatic redirects based on user language
 5+ *
 6+ * Features:
 7+ * * Magic redirects to localized page version
 8+ * * Interlanguage links in the sidebar point to localized local pages
 9+ *
 10+ * This can be combined with LanguageSelector and MultiLang to provide more internationalization support.
 11+ *
 12+ * See the README file for more information
 13+ *
 14+ * @package MediaWiki
 15+ * @subpackage Extensions
 16+ * @author Daniel Kinzler, brightbyte.de
 17+ * @copyright © 2007 Daniel Kinzler
 18+ * @licence GNU General Public Licence 2.0 or later
 19+ */
 20+
 21+if( !defined( 'MEDIAWIKI' ) ) {
 22+ echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
 23+ die( 1 );
 24+}
 25+
 26+$wgExtensionCredits['other'][] = array(
 27+ 'name' => 'Polyglot',
 28+ 'author' => 'Daniel Kinzler',
 29+ 'url' => 'http://mediawiki.org/wiki/Extension:Polyglot',
 30+ 'description' => 'support for content in multiple languages in a single mediawiki.',
 31+);
 32+
 33+/**
 34+* Set languages with polyglot support; applies to negotiation of interface language,
 35+* and to lookups for loclaized pages.
 36+* Set this to a small set of languages that are likely to be used on your site to
 37+* improve performance. Leave NULL to allow all languages known to MediaWiki via
 38+* $wgLanguageNames.
 39+* If the LanguageSelector extension is installed, $wgLanguageSelectorLanguages is used
 40+* as a fallback.
 41+*/
 42+$wgPolyglotLanguages = NULL;
 43+
 44+/**
 45+* Namespaces to excempt from polyglot support, with respect to automatic redirects.
 46+* All "magic" namespaces are excempt per default. There should be no reason to change this.
 47+* Note: internationalizing templates is best done on-page, using the MultiLang extension.
 48+*/
 49+$wfPolyglotExcemptNamespaces = array(NS_CATEGORY, NS_TEMPLATE, NS_IMAGE, NS_MEDIA, NS_SPECIAL, NS_MEDIAWIKI);
 50+
 51+/**
 52+* Wether talk pages should be excempt from automatic polyglot support, with respect to
 53+* automatic redirects. True per default.
 54+*/
 55+$wfPolyglotExcemptTalkPages = true;
 56+
 57+/**
 58+* Set to true if polyglot should resolve redirects that are encountered when applying an
 59+* automatic redirect to a localized page. This requires additional database access every
 60+* time a locaized page is accessed.
 61+*/
 62+$wfPolyglotFollowRedirects = false;
 63+
 64+///// hook it up /////////////////////////////////////////////////////
 65+$wgHooks['ArticleFromTitle'][] = 'wfPolyglotArticleFromTitle';
 66+$wgHooks['ParserAfterTidy'][] = 'wfPolyglotParserAfterTidy';
 67+$wgHooks['SkinTemplateOutputPageBeforeExec'][] = 'wfPolyglotSkinTemplateOutputPageBeforeExec';
 68+
 69+$wgExtensionFunctions[] = "wfPolyglotExtension";
 70+
 71+function wfPolyglotExtension() {
 72+ global $wgPolyglotLanguages;
 73+
 74+ if ( $wgPolyglotLanguages === NULL ) {
 75+ $wgPolyglotLanguages = @$GLOBALS['wgLanguageSelectorLanguages'];
 76+ }
 77+
 78+ if ( $wgPolyglotLanguages === NULL ) {
 79+ $wgPolyglotLanguages = array_keys( $GLOBALS['wgLanguageNames'] );
 80+ }
 81+}
 82+
 83+function wfPolyglotArticleFromTitle( &$title, &$article ) {
 84+ global $wfPolyglotExcemptNamespaces, $wfPolyglotExcemptTalkPages, $wfPolyglotFollowRedirects;
 85+ global $wgLang, $wgTitle, $wgRequest;
 86+
 87+ if ($wgRequest->getVal( 'redirect' ) == 'no') {
 88+ return true;
 89+ }
 90+
 91+ $ns = $title->getNamespace();
 92+
 93+ if ( $ns < 0
 94+ || in_array($ns, $wfPolyglotExcemptNamespaces)
 95+ || ($wfPolyglotExcemptTalkPages && Namespace::isTalk($ns)) ) {
 96+ return true;
 97+ }
 98+
 99+ $n = $title->getDBKey();
 100+ $nofollow = false;
 101+
 102+ //TODO: when user-defined language links start working (see below),
 103+ // we need to look at the langlinks table here.
 104+
 105+ if (!$title->exists() && strlen($n)>1 && preg_match('!/$!', $n)) {
 106+ $t = Title::makeTitle($ns, substr($n, 0, strlen($n)-1));
 107+ $nofollow = true;
 108+ }
 109+ else {
 110+ $lang = $wgLang->getCode();
 111+ $t = Title::makeTitle($ns, $n . '/' . $lang);
 112+ }
 113+
 114+ if (!$t->exists()) {
 115+ return true;
 116+ }
 117+
 118+ if ($wfPolyglotFollowRedirects && !$nofollow) {
 119+ $a = new Article($t);
 120+ $a->loadPageData();
 121+
 122+ if ($a->mIsRedirect) {
 123+ $rt = $a->followRedirect();
 124+ if ($rt && $rt->exists()) {
 125+ //TODO: make "redirected from" show $source, not $title, if we followed a redirect internally.
 126+ // there seems to be no clean way to do that, though.
 127+ //$source = $t;
 128+ $t = $rt;
 129+ }
 130+ }
 131+ }
 132+
 133+ if (!class_exists('PolyglotRedirect')) {
 134+ class PolyglotRedirect extends Article {
 135+ var $mTarget;
 136+
 137+ function __construct( $source, $target ) {
 138+ Article::__construct($source);
 139+ $this->mTarget = $target;
 140+ $this->mIsRedirect = true;
 141+ }
 142+
 143+ function followRedirect() {
 144+ return $this->mTarget;
 145+ }
 146+
 147+ function loadPageData( $data = 'fromdb' ) {
 148+ Article::loadPageData( $data );
 149+ $this->mIsRedirect = true;
 150+ }
 151+ }
 152+ }
 153+
 154+ //print $t->getFullText();
 155+
 156+ $article = new PolyglotRedirect( $title, $t ); //trigger redirect to lovcalized page
 157+
 158+ return true;
 159+}
 160+
 161+function wfPolyglotGetLanguages( $title ) {
 162+ global $wgPolyglotLanguages;
 163+ if (!$wgPolyglotLanguages) return NULL;
 164+
 165+ $n = $title->getDBKey();
 166+ $ns = $title->getNamespace();
 167+
 168+ $links = array();
 169+
 170+ foreach ($wgPolyglotLanguages as $lang) {
 171+ $t = Title::makeTitle($ns, $n . '/' . $lang);
 172+ if ($t->exists()) $links[$lang] = $t->getFullText();
 173+ }
 174+
 175+ return $links;
 176+}
 177+
 178+function wfPolyglotParserAfterTidy( &$parser, &$text ) {
 179+ global $wgPolyglotLanguages, $wfPolyglotExcemptNamespaces, $wfPolyglotExcemptTalkPages;
 180+ global $wgContLang;
 181+
 182+ if ( !$wgPolyglotLanguages ) return true;
 183+ if ( !$parser->mOptions->getInterwikiMagic() ) return true;
 184+
 185+ $n = $parser->mTitle->getDBKey();
 186+ $ns = $parser->mTitle->getNamespace();
 187+ $contln = $wgContLang->getCode();
 188+
 189+ $userlinks = $parser->mOutput->getLanguageLinks();
 190+
 191+ $links = array();
 192+ $pagelang = NULL;
 193+
 194+ //TODO: if we followed a redirect, analyze the redirect's title too.
 195+ // at least if wgPolyglotFollowRedirects is true
 196+
 197+ if ( $ns >= 0 && !in_array($ns, $wfPolyglotExcemptNamespaces)
 198+ && (!$wfPolyglotExcemptTalkPages || !Namespace::isTalk($ns)) ) {
 199+ $ll = wfPolyglotGetLanguages($parser->mTitle);
 200+ if ($ll) $links = array_merge($links, $ll);
 201+
 202+ if (preg_match('!(.+)/(\w[-\w]*\w)$!', $n, $m)) {
 203+ $pagelang = $m[2];
 204+ $t = Title::makeTitle($ns, $m[1]);
 205+ if (!isset($links[$contln]) && $t->exists()) $links[$contln] = $t->getFullText() . '/';
 206+
 207+ $ll = wfPolyglotGetLanguages($t);
 208+ if ($ll) {
 209+ unset($ll[$pagelang]);
 210+ $links = array_merge($links, $ll);
 211+ }
 212+ }
 213+ }
 214+
 215+ //TODO: would be nice to handle "normal" interwiki-links here.
 216+ // but we would have to hack into Title::getInterwikiLink, otherwise
 217+ // the links are not recognized.
 218+ /*
 219+ foreach ($userlinks as $link) {
 220+ $m = explode(':', $link, 2);
 221+ if (sizeof($m)<2) continue;
 222+
 223+ $links[$m[0]] = $m[1];
 224+ }
 225+ */
 226+
 227+ if ($pagelang) unset($links[$pagelang]);
 228+
 229+ //print_r($links);
 230+
 231+ $fakelinks = array();
 232+ foreach ($links as $lang => $t) {
 233+ $fakelinks[] = $lang . ':' . $t;
 234+ }
 235+
 236+ $parser->mOutput->setLanguageLinks($fakelinks);
 237+ return true;
 238+}
 239+
 240+function wfPolyglotSkinTemplateOutputPageBeforeExec($skin, $tpl) {
 241+ global $wgOut, $wgContLang;
 242+
 243+ $language_urls = array();
 244+ foreach( $wgOut->getLanguageLinks() as $l ) {
 245+ if (preg_match('!^(\w[-\w]*\w):(.+)$!', $l, $m)) {
 246+ $lang = $m[1];
 247+ $l = $m[2];
 248+ }
 249+ else {
 250+ continue; //NOTE: shouldn't happen
 251+ }
 252+
 253+ $nt = Title::newFromText( $l );
 254+ $language_urls[] = array(
 255+ 'href' => $nt->getFullURL(),
 256+ 'text' => $wgContLang->getLanguageName( $lang ),
 257+ 'class' => 'interwiki-' . $lang,
 258+ );
 259+ }
 260+
 261+ if(count($language_urls)) {
 262+ $tpl->setRef( 'language_urls', $language_urls);
 263+ } else {
 264+ $tpl->set('language_urls', false);
 265+ }
 266+
 267+ return true;
 268+}
 269+
 270+?>
\ No newline at end of file
Index: trunk/extensions/Polyglot/install.settings
@@ -0,0 +1,2 @@
 2+require_once( "{{path}}/Polyglot.php" );
 3+