* (bug 17160) Gender specific display text for User namespace
authorNiklas Laxström <nikerabbit@users.mediawiki.org>
Sat, 12 Feb 2011 20:40:40 +0000 (20:40 +0000)
committerNiklas Laxström <nikerabbit@users.mediawiki.org>
Sat, 12 Feb 2011 20:40:40 +0000 (20:40 +0000)
Second attempt for this thing..

RELEASE-NOTES
includes/AutoLoader.php
includes/GenderCache.php [new file with mode: 0644]
includes/LinkBatch.php
includes/LocalisationCache.php
includes/Namespace.php
includes/Title.php
languages/Language.php
languages/messages/MessagesEn.php

index 6b69b89..600dd6a 100644 (file)
@@ -176,6 +176,8 @@ MediaWiki supports over 330 languages. Many localisations are updated
 regularly. Below only new and removed languages are listed, as well as
 changes to languages because of Bugzilla reports.
 
+* (bug 17160) Gender specific display text for User namespace
+
 == Compatibility ==
 
 MediaWiki 1.18 requires PHP 5.1 (5.2 recommended). PHP 4 is no longer
index 1dc5e30..198f279 100644 (file)
@@ -98,6 +98,7 @@ $wgAutoloadLocalClasses = array(
        'ForkController' => 'includes/ForkController.php',
        'FormatExif' => 'includes/Exif.php',
        'FormOptions' => 'includes/FormOptions.php',
+       'GenderCache' => 'includes/GenderCache.php',
        'GlobalDependency' => 'includes/CacheDependency.php',
        'HashBagOStuff' => 'includes/BagOStuff.php',
        'HashtableReplacer' => 'includes/StringUtils.php',
diff --git a/includes/GenderCache.php b/includes/GenderCache.php
new file mode 100644 (file)
index 0000000..54ae60a
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * Caches user genders when needed to use correct namespace alises.
+ * @author Niklas Laxström
+ * @since 1.18
+ */
+class GenderCache {
+       protected $cache = array();
+       protected $default;
+       protected $misses = 0;
+       protected $missLimit = 1000;
+       
+       public static function singleton() {
+               static $that = null;
+               if ( $that === null ) {
+                       $that = new self();
+               }
+               return $that;
+       }
+
+       protected function __construct() {}
+
+       /**
+        * Returns the default gender option in this wiki.
+        * @return String
+        */
+       protected function getDefault() {
+               if ( $this->default === null ) {
+                       $this->default = User::getDefaultOption( 'gender' );
+               }
+               return $this->default;
+       }
+
+       /**
+        * Returns the gender for given username.
+        * @param $users String: username
+        * @param $caller String: the calling method
+        * @return String
+        */
+       public function getGenderOf( $username, $caller = '' ) {
+               global $wgUser;
+
+               $username = strtr( $username, '_', ' ' );
+               if ( !isset( $this->cache[$username] ) ) {
+
+                       if ( $this->misses >= $this->missLimit && $wgUser->getName() !== $username ) {
+                               if( $this->misses === $this->missLimit ) {
+                                       $this->misses++;
+                                       wfDebug( __METHOD__ . ": too many misses, returning default onwards\n" );
+                               }
+                               return $this->getDefault();
+
+                       } else {
+                               $this->misses++;
+                               if ( !User::isValidUserName( $username ) ) {
+                                       $this->cache[$username] = $this->getDefault();
+                               } else {
+                                       $this->doQuery( $username, $caller );
+                               }
+                       }
+
+               }
+
+               /* Undefined if there is a valid username which for some reason doesn't
+                * exist in the database.
+                */
+               return isset( $this->cache[$username] ) ? $this->cache[$username] : $this->getDefault();
+       }
+
+       /**
+        * Wrapper for doQuery that processes raw LinkBatch data.
+        */
+       public function doLinkBatch( $data, $caller = '' ) {
+               $users = array();
+               foreach ( $data as $ns => $pagenames ) {
+                       if ( !MWNamespace::hasGenderDistinction( $ns ) ) continue;
+                       foreach ( array_keys( $pagenames ) as $username ) {
+                               if ( isset( $this->cache[$username] ) ) continue;
+                               $users[$username] = true;
+                       }
+               }
+
+               $this->doQuery( array_keys( $users ), $caller );
+
+       }
+
+       /**
+        * Preloads genders for given list of users.
+        * @param $users List|String: usernames
+        * @param $caller String: the calling method
+        */
+       public function doQuery( $users, $caller = '' ) {
+               if ( count( $users ) === 0 ) return false;
+
+               foreach ( (array) $users as $index => $value ) {
+                       $users[$index] = strtr( $value, '_', ' ' );
+               }
+
+               $dbr = wfGetDB( DB_SLAVE );
+               $table = array( 'user', 'user_properties' );
+               $fields = array( 'user_name', 'up_value' );
+               $conds = array( 'user_name' => $users );
+               $joins = array( 'user_properties' =>
+                       array( 'LEFT JOIN', array( 'user_id = up_user', 'up_property' => 'gender' ) ) );
+
+               $comment = __METHOD__;
+               if ( strval( $caller ) !== '' ) {
+                       $comment .= "/$caller";
+               }
+               $res = $dbr->select( $table, $fields, $conds, $comment, $joins, $joins );
+
+               $default = $this->getDefault();
+               foreach ( $res as $row ) {
+                       $this->cache[$row->user_name] = $row->up_value ? $row->up_value : $default;
+               }
+       }
+
+}
index 77c4edd..9486815 100644 (file)
@@ -94,6 +94,7 @@ class LinkBatch {
                wfProfileIn( __METHOD__ );
                $res = $this->doQuery();
                $ids = $this->addResultToCache( $cache, $res );
+               $this->doGenderQuery();
                wfProfileOut( __METHOD__ );
                return $ids;
        }
@@ -157,6 +158,20 @@ class LinkBatch {
                return $res;
        }
 
+       public function doGenderQuery() {
+               if ( $this->isEmpty() ) {
+                       return false;
+               }
+
+               global $wgContLang;
+               if ( !$wgContLang->needsGenderDistinction() ) {
+                       return false;
+               }
+
+               $genderCache = GenderCache::singleton();
+               $genderCache->dolinkBatch( $this->data, $this->caller );
+       }
+
        /**
         * Construct a WHERE clause which will match all the given titles.
         *
index d8551a0..af2ed65 100644 (file)
@@ -87,7 +87,7 @@ class LocalisationCache {
                'defaultUserOptionOverrides', 'linkTrail', 'namespaceAliases',
                'dateFormats', 'datePreferences', 'datePreferenceMigrationMap',
                'defaultDateFormat', 'extraUserToggles', 'specialPageAliases',
-               'imageFiles', 'preloadedMessages',
+               'imageFiles', 'preloadedMessages', 'namespaceGenderAliases',
        );
 
        /**
index 4753aaa..2e4b789 100644 (file)
@@ -276,4 +276,17 @@ class MWNamespace {
                // Default to the global setting
                return $wgCapitalLinks;
        }
+
+       /**
+        * Does the namespace (potentially) have different aliases for different
+        * genders. Not all languages make a distinction here.
+        *
+        * @since 1.18
+        * @param $index int Index to check
+        * @return bool
+        */
+       public static function hasGenderDistinction( $index ) {
+               return $index == NS_USER || $index == NS_USER_TALK;
+       }
+
 }
index 54e2dce..e2e8dee 100644 (file)
@@ -617,6 +617,13 @@ class Title {
                                return MWNamespace::getCanonicalName( $this->mNamespace );
                        }
                }
+
+               if ( $wgContLang->needsGenderDistinction() &&
+                               MWNamespace::hasGenderDistinction( $this->mNamespace ) ) {
+                       $gender = GenderCache::singleton()->getGenderOf( $this->getText(), __METHOD__ );
+                       return $wgContLang->getGenderNsText( $this->mNamespace, $gender );
+               }
+
                return $wgContLang->getNsText( $this->mNamespace );
        }
 
index 50ac78a..10bb29d 100644 (file)
@@ -338,6 +338,29 @@ class Language {
                return strtr( $ns, '_', ' ' );
        }
 
+       /**
+        * Returns gender-dependent namespace alias if available.
+        * @param $index Int: namespace index
+        * @param $gender String: gender key (male, female... )
+        * @return String
+        * @since 1.18
+        */
+       function getGenderNsText( $index, $gender ) {
+               $ns = self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
+               return isset( $ns[$index][$gender] ) ? $ns[$index][$gender] : $this->getNsText( $index );
+       }
+
+       /**
+        * Whether this language makes distinguishes genders for example in
+        * namespaces.
+        * @return bool
+        * @since 1.18
+        */
+       function needsGenderDistinction() {
+               $aliases = self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
+               return count( $aliases ) > 0;
+       }
+
        /**
         * Get a namespace key by value, case insensitive.
         * Only matches namespace names for the current language, not the
@@ -366,6 +389,14 @@ class Language {
                                        }
                                }
                        }
+
+                       $genders = self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
+                       foreach ( $genders as $index => $forms ) {
+                               foreach ( $forms as $alias ) {
+                                       $aliases[$alias] = $index;
+                               }
+                       }
+
                        $this->namespaceAliases = $aliases;
                }
                return $this->namespaceAliases;
index 7e1fa32..299d978 100644 (file)
@@ -111,6 +111,16 @@ $namespaceNames = array(
  */
 $namespaceAliases = array();
 
+/**
+ * Array of gender specific. namespace aliases.
+ * Mapping NS_xxx to array of GENDERKEY to alias.
+ * Example:
+$namespaceGenderAliases = array(
+       NS_USER => array( 'male' => 'Male_user', 'female' => 'Female_user' ),
+);
+ */
+$namespaceGenderAliases = array();
+
 /**
  * Deprecated, use the message array
  */