r91439 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r91438‎ | r91439 | r91440 >
Date:06:08, 5 July 2011
Author:jan
Status:ok (Comments)
Tags:
Comment:
Add PLURAL-support
Modified paths:
  • /trunk/tools/ToolserverI18N/TsIntuition.php (modified) (history)
  • /trunk/tools/ToolserverI18N/language/MessagesFunctions.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LICENSE.txt (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/Language.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageAm.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageAr.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageAz.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageBe.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageBe_tarask.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageBg.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageBh.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageBs.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageConverter.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageCs.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageCu.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageCy.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageDsb.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageEo.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageEt.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageFi.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageFr.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageGa.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageGan.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageGd.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageGv.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageHe.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageHi.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageHr.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageHsb.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageHu.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageHy.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageIu.deps.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageIu.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageJa.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageKaa.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageKk.deps.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageKk.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageKk_cyrl.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageKm.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageKsh.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageKu.deps.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageKu.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageKu_ku.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageLa.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageLn.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageLt.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageLv.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageMg.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageMk.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageMl.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageMo.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageMt.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageMy.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageNso.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguagePl.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageRo.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageRu.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSe.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSgs.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSh.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSk.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSl.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSma.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSr.deps.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSr.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSr_ec.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSr_el.deps.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageSr_el.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageTg.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageTi.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageTl.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageTr.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageTyv.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageUk.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageWa.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageYue.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageZh.deps.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageZh.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/LanguageZh_hans.php (added) (history)
  • /trunk/tools/ToolserverI18N/language/classes/Names.php (added) (history)

Diff [purge]

Index: trunk/tools/ToolserverI18N/TsIntuition.php
@@ -82,6 +82,9 @@
8383
8484 // Redirect address and status
8585 private $redirectTo = null;
 86+
 87+ // Object of MessagesFunctions
 88+ private $messagesFunctions = null;
8689
8790 /* Init
8891 * ------------------------------------------------- */
@@ -328,6 +331,20 @@
329332 return false;
330333 }
331334
 335+ /**
 336+ * Get a instance of MessagesFunctions
 337+ *
 338+ * @return Object of MessagesFunction
 339+ */
 340+ private function getMessagesFunctions() {
 341+ if ( $this->messagesFunctions == null ) {
 342+ require_once( $this->localBaseDir . '/language/MessagesFunctions.php' );
 343+ $this->messagesFunctions = MessagesFunctions::getInstance( $this->localBaseDir, $this );
 344+ return $this->messagesFunctions;
 345+ } else {
 346+ return $this->messagesFunctions;
 347+ }
 348+ }
332349
333350 /* Message functions
334351 * ------------------------------------------------- */
@@ -342,6 +359,7 @@
343360 * - lang: overrides the currently selected language
344361 * - variables: numerical array to do variable replacements ($1> var[0], $2> var[1], etc.)
345362 * - raw-variables: boolean to determine whether the variables should be escaped as well
 363+ * - parse: boolean to determine whether the message sould be parsed (PLURAL, etc.)
346364 * - escape: Optionally the return can be escaped. By default this takes place after variable
347365 * replacement. Set 'raw-variables' to true if you just want the raw message
348366 * to be escaped and have escaped the variables already.
@@ -364,6 +382,7 @@
365383 'variables' => array(),
366384 'raw-variables' => false,
367385 'escape' => 'plain',
 386+ 'parse' => false,
368387 );
369388
370389 // If $options was a domain string, convert it now.
@@ -418,6 +437,11 @@
419438 $n = $i + 1;
420439 $msg = str_replace( "\$$n", $val, $msg );
421440 }
 441+
 442+ // Some parsing work
 443+ if ( $options['parse'] === true ) {
 444+ $msg = $this->getMessagesFunctions()->parse( $msg, $lang );
 445+ }
422446
423447 // If not already escaped, do it now
424448 if ( !$escapeDone ) {
@@ -816,17 +840,25 @@
817841 * ------------------------------------------------- */
818842
819843 /**
820 - * @TODO:
 844+ * FIXME: Implement in language/MessagesFunctions.php.
 845+ *
 846+ * @todo
821847 */
822848 public function gender( $male, $female, $neutral ) {
823849 // Depends on getGender() which doesn't exist yet
 850+ throw new BadMethodCallException("Not supported yet!");
824851 }
825852
826853 /**
827 - * @TODO:
 854+ * Can be founded in language/MessagesFunctions.php.
 855+ *
 856+ * @see MessagesFunctions::parse
 857+ * @see MessagesFunctions::plural
 858+ * @deprecated
828859 */
829860 public function plural( $count, $forms ) {
830 - // Todo
 861+ throw new BadMethodCallException(
 862+ "Use msg() with \"parse\" option to support PLURAL!");
831863 }
832864
833865
@@ -1210,7 +1242,7 @@
12111243 }
12121244
12131245 // Custom version of trigger_error() that can be passed a custom filename and line number
1214 - private function errTrigger( $msg, $context, $level = E_WARNING, $file = '', $line = '' ) {
 1246+ public function errTrigger( $msg, $context, $level = E_WARNING, $file = '', $line = '' ) {
12151247 $die = false;
12161248 $error = false;
12171249 $notice = false;
Index: trunk/tools/ToolserverI18N/language/MessagesFunctions.php
@@ -0,0 +1,175 @@
 2+<?PHP
 3+/**
 4+ *
 5+ * Functions for messages (PLURAL, etc.).
 6+ *
 7+ * @package TsIntuition
 8+ * @author Jan Luca <jan@toolserver.org>
 9+ * @see TsIntuition::msg()
 10+ */
 11+
 12+class MessagesFunctions {
 13+ private static $instance = null;
 14+
 15+ private $langIsLoaded = array();
 16+
 17+ private $baseDir = null;
 18+
 19+ private $I18N = null;
 20+
 21+ private $pluralRegex = "@\\{\\{PLURAL\\:(.*?)\\|(.*?)\\}\\}@i";
 22+
 23+ private $error = array();
 24+
 25+ /**
 26+ *
 27+ * Get a instance of MessagesFunctions.
 28+ *
 29+ * @param String $baseDir The path of the root dir of TS-I18N
 30+ * @param TsIntuition $I18N The current object of TsIntution
 31+ * @static
 32+ * @see TsIntuition::getMessagesFunctions()
 33+ */
 34+ public static function getInstance( $baseDir, $I18N ) {
 35+ if( self::$instance == null ) {
 36+ self::$instance = new MessagesFunctions( $baseDir, $I18N );
 37+ return self::$instance;
 38+ } else {
 39+ return self::$instance;
 40+ }
 41+ }
 42+
 43+ /**
 44+ *
 45+ * Construct a new object of MessageFunctions.
 46+ *
 47+ * @param String $baseDir The path of the root dir of TS-I18N
 48+ * @param TsIntuition $I18N The current object of TsIntution
 49+ */
 50+ function __construct( $baseDir, $I18N ) {
 51+ $this->baseDir = $baseDir;
 52+ $this->I18N = $I18N;
 53+
 54+ require_once( $this->baseDir."/language/classes/Language.php" );
 55+ }
 56+
 57+ /**
 58+ *
 59+ * Load a language class file from its code.
 60+ *
 61+ * @param String $language Language-Code
 62+ */
 63+ private function loadLanguage( $language ) {
 64+ $language = ucfirst( strtolower( str_replace("-", "_", $language ) ) );
 65+
 66+ if ( in_array( $language, $this->langIsLoaded ) ) {
 67+ return;
 68+ }
 69+
 70+ $className = "Language".$language;
 71+
 72+ if ( file_exists( $this->baseDir."/language/classes/".$className.".php" ) ) {
 73+ include_once( $this->baseDir."/language/classes/".$className.".php" );
 74+ }
 75+
 76+ $this->langIsLoaded[] = $language;
 77+ }
 78+
 79+ /**
 80+ *
 81+ * Get the functions (PLURAL, etc.) from the message.
 82+ *
 83+ * @param String $msg the message with the functions
 84+ * @return array of the functions
 85+ */
 86+ private function getMsgFunctions( $msg ) {
 87+ $functions = array();
 88+
 89+ if ( preg_match_all($this->pluralRegex, $msg, $matches, PREG_SET_ORDER) ) {
 90+ foreach( $matches as $match ) {
 91+ $parameteres = array();
 92+ $parameteres[] = "plural";
 93+ $parameteres[] = trim($match[1]);
 94+
 95+ $forms = explode( "|", $match[2] );
 96+ foreach( $forms as $form ) {
 97+ $parameteres[] = $form;
 98+ }
 99+
 100+ $functions[] = $parameteres;
 101+ }
 102+ }
 103+
 104+ return $functions;
 105+ }
 106+
 107+ /**
 108+ *
 109+ * Parsing a message.
 110+ *
 111+ * @param String $msg Message
 112+ * @param String $lang Language of the message
 113+ * @return String Parsed message
 114+ */
 115+ public function parse( $msg, $lang ) {
 116+ $this->loadLanguage( $lang );
 117+
 118+ $msgFunctions = $this->getMsgFunctions( $msg );
 119+
 120+ foreach( $msgFunctions as $msgFunction ) {
 121+ $functionName = array_shift( $msgFunction );
 122+ $functionNumber = array_shift( $msgFunction );
 123+ if ( $functionNumber != null ) {
 124+ $msg = $this->$functionName( $functionNumber, $msgFunction, $msg, $lang );
 125+ } else {
 126+ $msg = $this->$functionName( $msgFunction, $msg, $lang );
 127+ }
 128+ }
 129+
 130+ $this->sendParseErrors( __METHOD__ );
 131+
 132+ return $msg;
 133+ }
 134+
 135+ private function plural( $number, $parameters, $msg, $language ) {
 136+ $language = ucfirst( strtolower( str_replace("-", "_", $language ) ) );
 137+
 138+ if ( !is_numeric( $number ) ) {
 139+ $this->addParseError( "Invalid number argument to {{PLURAL: ...}}",
 140+ __METHOD__, E_ERROR, __FILE__, __LINE__ );
 141+ return $msg;
 142+ }
 143+
 144+ $className = "Language".$language;
 145+
 146+ if ( class_exists( $className ) ) {
 147+ $langObj = new $className();
 148+ } else {
 149+ $langObj = new Language();
 150+ }
 151+
 152+ $form = $langObj->convertPlural( $number, $parameters );
 153+
 154+ $msg = preg_replace( $this->pluralRegex, $form, $msg, 1 );
 155+
 156+ return $msg;
 157+ }
 158+
 159+ private function addParseError( $errMsg, $context, $errType = E_WARNING, $file = '', $line = '' ) {
 160+ $this->error[] = array( "msg" => $errMsg, "context" => $context,
 161+ "type" => $errType, "file" => $file, "line" => $line );
 162+ }
 163+
 164+ private function sendParseErrors( $parseContext ) {
 165+ if ( count( $this->error ) < 1 ) return;
 166+
 167+ $this->I18N->errTrigger( "Problems when parsing the message. For Information see below!",
 168+ $parseContext, E_WARNING );
 169+
 170+ foreach( $this->error as $error ) {
 171+ $this->I18N->errTrigger( $error["msg"], $error["context"],
 172+ $error["type"], $error["file"], $error["line"] );
 173+ }
 174+ }
 175+}
 176+?>
\ No newline at end of file
Property changes on: trunk/tools/ToolserverI18N/language/MessagesFunctions.php
___________________________________________________________________
Added: svn:eol-style
1177 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageHe.php
@@ -0,0 +1,70 @@
 2+<?php
 3+
 4+/**
 5+ * Hebrew (עברית)
 6+ *
 7+ * @ingroup Language
 8+ *
 9+ * @author Rotem Liss
 10+ */
 11+class LanguageHe extends Language {
 12+
 13+ /**
 14+ * Convert grammar forms of words.
 15+ *
 16+ * Available cases:
 17+ * "prefixed" (or "תחילית") - when the word has a prefix
 18+ *
 19+ * @param $word String: the word to convert
 20+ * @param $case String: the case
 21+ *
 22+ * @return string
 23+ */
 24+ public function convertGrammar( $word, $case ) {
 25+ global $wgGrammarForms;
 26+ if ( isset( $wgGrammarForms['he'][$case][$word] ) ) {
 27+ return $wgGrammarForms['he'][$case][$word];
 28+ }
 29+
 30+ switch ( $case ) {
 31+ case 'prefixed':
 32+ case 'תחילית':
 33+ # Duplicate the "Waw" if prefixed
 34+ if ( substr( $word, 0, 2 ) == "ו" && substr( $word, 0, 4 ) != "וו" ) {
 35+ $word = "ו" . $word;
 36+ }
 37+
 38+ # Remove the "He" if prefixed
 39+ if ( substr( $word, 0, 2 ) == "ה" ) {
 40+ $word = substr( $word, 2 );
 41+ }
 42+
 43+ # Add a hyphen if non-Hebrew letters
 44+ if ( substr( $word, 0, 2 ) < "א" || substr( $word, 0, 2 ) > "ת" ) {
 45+ $word = "־" . $word;
 46+ }
 47+ }
 48+
 49+ return $word;
 50+ }
 51+
 52+ /**
 53+ * Gets a number and uses the suited form of the word.
 54+ *
 55+ * @param $count Integer: the number of items
 56+ * @param $forms Array with 3 items: the three plural forms
 57+ * @return String: the suited form of word
 58+ */
 59+ function convertPlural( $count, $forms ) {
 60+ if ( !count( $forms ) ) { return ''; }
 61+ $forms = $this->preConvertPlural( $forms, 3 );
 62+
 63+ if ( $count == '1' ) {
 64+ return $forms[0];
 65+ } elseif ( $count == '2' && isset( $forms[2] ) ) {
 66+ return $forms[2];
 67+ } else {
 68+ return $forms[1];
 69+ }
 70+ }
 71+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageHe.php
___________________________________________________________________
Added: svn:eol-style
172 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageLa.php
@@ -0,0 +1,83 @@
 2+<?php
 3+
 4+/** Latin (lingua Latina)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageLa extends Language {
 9+ /**
 10+ * Convert from the nominative form of a noun to some other case
 11+ *
 12+ * Just used in a couple places for sitenames; special-case as necessary.
 13+ * Rules are far from complete.
 14+ *
 15+ * Cases: genitive, accusative, ablative
 16+ *
 17+ * @param $word string
 18+ * @param $case string
 19+ *
 20+ * @return string
 21+ */
 22+ function convertGrammar( $word, $case ) {
 23+ global $wgGrammarForms;
 24+ if ( isset( $wgGrammarForms['la'][$case][$word] ) ) {
 25+ return $wgGrammarForms['la'][$case][$word];
 26+ }
 27+
 28+ switch ( $case ) {
 29+ case 'genitive':
 30+ // only a few declensions, and even for those mostly the singular only
 31+ $in = array( '/u[ms]$/', # 2nd declension singular
 32+ '/ommunia$/', # 3rd declension neuter plural (partly)
 33+ '/a$/', # 1st declension singular
 34+ '/libri$/', '/nuntii$/', # 2nd declension plural (partly)
 35+ '/tio$/', '/ns$/', '/as$/', # 3rd declension singular (partly)
 36+ '/es$/' # 5th declension singular
 37+ );
 38+ $out = array( 'i',
 39+ 'ommunium',
 40+ 'ae',
 41+ 'librorum', 'nuntiorum',
 42+ 'tionis', 'ntis', 'atis',
 43+ 'ei'
 44+ );
 45+ return preg_replace( $in, $out, $word );
 46+ case 'accusative':
 47+ // only a few declensions, and even for those mostly the singular only
 48+ $in = array( '/u[ms]$/', # 2nd declension singular
 49+ '/a$/', # 1st declension singular
 50+ '/ommuniam$/', # 3rd declension neuter plural (partly)
 51+ '/libri$/', '/nuntii$/', # 2nd declension plural (partly)
 52+ '/tio$/', '/ns$/', '/as$/', # 3rd declension singular (partly)
 53+ '/es$/' # 5th declension singular
 54+ );
 55+ $out = array( 'um',
 56+ 'am',
 57+ 'ommunia',
 58+ 'libros', 'nuntios',
 59+ 'tionem', 'ntem', 'atem',
 60+ 'em'
 61+ );
 62+ return preg_replace( $in, $out, $word );
 63+ case 'ablative':
 64+ // only a few declensions, and even for those mostly the singular only
 65+ $in = array( '/u[ms]$/', # 2nd declension singular
 66+ '/ommunia$/', # 3rd declension neuter plural (partly)
 67+ '/a$/', # 1st declension singular
 68+ '/libri$/', '/nuntii$/', # 2nd declension plural (partly)
 69+ '/tio$/', '/ns$/', '/as$/', # 3rd declension singular (partly)
 70+ '/es$/' # 5th declension singular
 71+ );
 72+ $out = array( 'o',
 73+ 'ommunibus',
 74+ 'a',
 75+ 'libris', 'nuntiis',
 76+ 'tione', 'nte', 'ate',
 77+ 'e'
 78+ );
 79+ return preg_replace( $in, $out, $word );
 80+ default:
 81+ return $word;
 82+ }
 83+ }
 84+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageLa.php
___________________________________________________________________
Added: svn:eol-style
185 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageHi.php
@@ -0,0 +1,22 @@
 2+<?php
 3+/**
 4+ * Hindi (हिन्दी)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageHi extends Language {
 9+ /**
 10+ * Use singular form for zero
 11+ *
 12+ * @param $count int
 13+ * @param $forms array
 14+ *
 15+ * @return string
 16+ */
 17+ function convertPlural( $count, $forms ) {
 18+ if ( !count( $forms ) ) { return ''; }
 19+ $forms = $this->preConvertPlural( $forms, 2 );
 20+
 21+ return ( $count <= 1 ) ? $forms[0] : $forms[1];
 22+ }
 23+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageHi.php
___________________________________________________________________
Added: svn:eol-style
124 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageIu.deps.php
@@ -0,0 +1,8 @@
 2+<?php
 3+// This file exists to ensure that base classes are preloaded before
 4+// LanguageIu.php is compiled, working around a bug in the APC opcode
 5+// cache on PHP 5, where cached code can break if the include order
 6+// changed on a subsequent page view.
 7+// see http://mail.wikipedia.org/pipermail/wikitech-l/2006-January/033660.html
 8+
 9+require_once( dirname(__FILE__).'/../LanguageConverter.php' );
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageIu.deps.php
___________________________________________________________________
Added: svn:eol-style
110 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageHr.php
@@ -0,0 +1,32 @@
 2+<?php
 3+/** Croatian (hrvatski)
 4+ *
 5+ * @ingroup Language
 6+ */
 7+
 8+class LanguageHr extends Language {
 9+
 10+ /**
 11+ * @param $count int
 12+ * @param $forms array
 13+ * @return string
 14+ */
 15+ function convertPlural( $count, $forms ) {
 16+ if ( !count( $forms ) ) { return ''; }
 17+ // @todo FIXME: CLDR defines 4 plural forms instead of 3. Plural for for decimals is missing.
 18+ // http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
 19+ $forms = $this->preConvertPlural( $forms, 3 );
 20+
 21+ if ( $count > 10 && floor( ( $count % 100 ) / 10 ) == 1 ) {
 22+ return $forms[2];
 23+ } else {
 24+ switch ( $count % 10 ) {
 25+ case 1: return $forms[0];
 26+ case 2:
 27+ case 3:
 28+ case 4: return $forms[1];
 29+ default: return $forms[2];
 30+ }
 31+ }
 32+ }
 33+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageHr.php
___________________________________________________________________
Added: svn:eol-style
134 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageKu.deps.php
@@ -0,0 +1,9 @@
 2+<?php
 3+// This file exists to ensure that base classes are preloaded before
 4+// LanguageKu.php is compiled, working around a bug in the APC opcode
 5+// cache on PHP 5, where cached code can break if the include order
 6+// changed on a subsequent page view.
 7+// see http://lists.wikimedia.org/pipermail/wikitech-l/2006-January/021311.html
 8+
 9+require_once( dirname( __FILE__ ) . '/../LanguageConverter.php' );
 10+require_once( dirname( __FILE__ ) . '/LanguageKu_ku.php' );
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageKu.deps.php
___________________________________________________________________
Added: svn:eol-style
111 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageLn.php
@@ -0,0 +1,23 @@
 2+<?php
 3+/**
 4+ * Lingala (Lingála)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageLn extends Language {
 9+ /**
 10+ * Use singular form for zero
 11+ * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ln
 12+ *
 13+ * @param $count int
 14+ * @param $forms array
 15+ *
 16+ * @return string
 17+ */
 18+ function convertPlural( $count, $forms ) {
 19+ if ( !count( $forms ) ) { return ''; }
 20+ $forms = $this->preConvertPlural( $forms, 2 );
 21+
 22+ return ( $count <= 1 ) ? $forms[0] : $forms[1];
 23+ }
 24+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageLn.php
___________________________________________________________________
Added: svn:eol-style
125 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageTg.php
@@ -0,0 +1,106 @@
 2+<?php
 3+
 4+require_once( dirname( __FILE__ ) . '/../LanguageConverter.php' );
 5+
 6+/**
 7+ * Converts Tajiki to latin orthography
 8+ * @ingroup Language
 9+ */
 10+class TgConverter extends LanguageConverter {
 11+ private $table = array(
 12+ 'а' => 'a',
 13+ 'б' => 'b',
 14+ 'в' => 'v',
 15+ 'г' => 'g',
 16+ 'д' => 'd',
 17+ 'е' => 'e',
 18+ 'ё' => 'jo',
 19+ 'ж' => 'ƶ',
 20+ 'з' => 'z',
 21+ 'ии ' => 'iji ',
 22+ 'и' => 'i',
 23+ 'й' => 'j',
 24+ 'к' => 'k',
 25+ 'л' => 'l',
 26+ 'м' => 'm',
 27+ 'н' => 'n',
 28+ 'о' => 'o',
 29+ 'п' => 'p',
 30+ 'р' => 'r',
 31+ 'с' => 's',
 32+ 'т' => 't',
 33+ 'у' => 'u',
 34+ 'ф' => 'f',
 35+ 'х' => 'x',
 36+ 'ч' => 'c',
 37+ 'ш' => 'ş',
 38+ 'ъ' => '\'',
 39+ 'э' => 'e',
 40+ 'ю' => 'ju',
 41+ 'я' => 'ja',
 42+ 'ғ' => 'ƣ',
 43+ 'ӣ' => 'ī',
 44+ 'қ' => 'q',
 45+ 'ӯ' => 'ū',
 46+ 'ҳ' => 'h',
 47+ 'ҷ' => 'ç',
 48+ 'ц' => 'ts',
 49+ 'А' => 'A',
 50+ 'Б' => 'B',
 51+ 'В' => 'V',
 52+ 'Г' => 'G',
 53+ 'Д' => 'D',
 54+ 'Е' => 'E',
 55+ 'Ё' => 'Jo',
 56+ 'Ж' => 'Ƶ',
 57+ 'З' => 'Z',
 58+ 'И' => 'I',
 59+ 'Й' => 'J',
 60+ 'К' => 'K',
 61+ 'Л' => 'L',
 62+ 'М' => 'M',
 63+ 'Н' => 'N',
 64+ 'О' => 'O',
 65+ 'П' => 'P',
 66+ 'Р' => 'R',
 67+ 'С' => 'S',
 68+ 'Т' => 'T',
 69+ 'У' => 'U',
 70+ 'Ф' => 'F',
 71+ 'Х' => 'X',
 72+ 'Ч' => 'C',
 73+ 'Ш' => 'Ş',
 74+ 'Ъ' => '\'',
 75+ 'Э' => 'E',
 76+ 'Ю' => 'Ju',
 77+ 'Я' => 'Ja',
 78+ 'Ғ' => 'Ƣ',
 79+ 'Ӣ' => 'Ī',
 80+ 'Қ' => 'Q',
 81+ 'Ӯ' => 'Ū',
 82+ 'Ҳ' => 'H',
 83+ 'Ҷ' => 'Ç',
 84+ 'Ц' => 'Ts',
 85+ );
 86+
 87+ function loadDefaultTables() {
 88+ $this->mTables = array(
 89+ 'tg-latn' => new ReplacementArray( $this->table ),
 90+ 'tg' => new ReplacementArray()
 91+ );
 92+ }
 93+
 94+}
 95+
 96+/**
 97+ * Tajik (Тоҷикӣ)
 98+ *
 99+ * @ingroup Language
 100+ */
 101+class LanguageTg extends Language {
 102+ function __construct() {
 103+ parent::__construct();
 104+ $variants = array( 'tg', 'tg-latn' );
 105+ $this->mConverter = new TgConverter( $this, 'tg', $variants );
 106+ }
 107+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageTg.php
___________________________________________________________________
Added: svn:eol-style
1108 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguagePl.php
@@ -0,0 +1,42 @@
 2+<?php
 3+
 4+/** Polish (polski)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguagePl extends Language {
 9+
 10+ /**
 11+ * @param $count string
 12+ * @param $forms array
 13+ * @return string
 14+ */
 15+ function convertPlural( $count, $forms ) {
 16+ if ( !count( $forms ) ) { return ''; }
 17+ $forms = $this->preConvertPlural( $forms, 3 );
 18+ $count = abs( $count );
 19+ if ( $count == 1 )
 20+ return $forms[0]; // singular
 21+ switch ( $count % 10 ) {
 22+ case 2:
 23+ case 3:
 24+ case 4:
 25+ if ( $count / 10 % 10 != 1 )
 26+ return $forms[1]; // plural
 27+ default:
 28+ return $forms[2]; // plural genitive
 29+ }
 30+ }
 31+
 32+ /**
 33+ * @param $_ string
 34+ * @return string
 35+ */
 36+ function commafy( $_ ) {
 37+ if ( !preg_match( '/^\-?\d{1,4}(\.\d+)?$/', $_ ) ) {
 38+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 39+ } else {
 40+ return $_;
 41+ }
 42+ }
 43+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguagePl.php
___________________________________________________________________
Added: svn:eol-style
144 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageTi.php
@@ -0,0 +1,22 @@
 2+<?php
 3+/**
 4+ * Tigrinya (ትግርኛ)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageTi extends Language {
 9+ /**
 10+ * Use singular form for zero
 11+ *
 12+ * @param $count int
 13+ * @param $forms array
 14+ *
 15+ * @return string
 16+ */
 17+ function convertPlural( $count, $forms ) {
 18+ if ( !count( $forms ) ) { return ''; }
 19+ $forms = $this->preConvertPlural( $forms, 2 );
 20+
 21+ return ( $count <= 1 ) ? $forms[0] : $forms[1];
 22+ }
 23+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageTi.php
___________________________________________________________________
Added: svn:eol-style
124 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageHu.php
@@ -0,0 +1,29 @@
 2+<?php
 3+
 4+/** Hungarian localisation for MediaWiki
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageHu extends Language {
 9+
 10+ /**
 11+ * @param $word string
 12+ * @param $case
 13+ * @return string
 14+ */
 15+ function convertGrammar( $word, $case ) {
 16+ global $wgGrammarForms;
 17+ if ( isset( $wgGrammarForms[$this->getCode()][$case][$word] ) ) {
 18+ return $wgGrammarForms[$this->getCode()][$case][$word];
 19+ }
 20+
 21+ switch ( $case ) {
 22+ case 'rol':
 23+ return $word . 'ról';
 24+ case 'ba':
 25+ return $word . 'ba';
 26+ case 'k':
 27+ return $word . 'k';
 28+ }
 29+ }
 30+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageHu.php
___________________________________________________________________
Added: svn:eol-style
131 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageTl.php
@@ -0,0 +1,22 @@
 2+<?php
 3+/**
 4+ * Tagalog (Tagalog)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageTl extends Language {
 9+ /**
 10+ * Use singular form for zero
 11+ *
 12+ * @param $count int
 13+ * @param $forms array
 14+ *
 15+ * @return string
 16+ */
 17+ function convertPlural( $count, $forms ) {
 18+ if ( !count( $forms ) ) { return ''; }
 19+ $forms = $this->preConvertPlural( $forms, 2 );
 20+
 21+ return ( $count <= 1 ) ? $forms[0] : $forms[1];
 22+ }
 23+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageTl.php
___________________________________________________________________
Added: svn:eol-style
124 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageLt.php
@@ -0,0 +1,32 @@
 2+<?php
 3+
 4+/** Lithuanian (Lietuvių)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageLt extends Language {
 9+ /* Word forms (with examples):
 10+ 1 - vienas (1) lapas, dvidešimt vienas (21) lapas
 11+ 2 - trys (3) lapai
 12+ 3 - penkiolika (15) lapų
 13+ */
 14+
 15+ /**
 16+ * @param $count int
 17+ * @param $forms array
 18+ *
 19+ * @return string
 20+ */
 21+ function convertPlural( $count, $forms ) {
 22+ if ( !count( $forms ) ) { return ''; }
 23+
 24+ // if no number with word, then use $form[0] for singular and $form[1] for plural or zero
 25+ if ( count( $forms ) === 2 ) return $count == 1 ? $forms[0] : $forms[1];
 26+
 27+ $forms = $this->preConvertPlural( $forms, 3 );
 28+
 29+ if ( $count % 10 == 1 && $count % 100 != 11 ) return $forms[0];
 30+ if ( $count % 10 >= 2 && ( $count % 100 < 10 || $count % 100 >= 20 ) ) return $forms[1];
 31+ return $forms[2];
 32+ }
 33+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageLt.php
___________________________________________________________________
Added: svn:eol-style
134 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageHy.php
@@ -0,0 +1,85 @@
 2+<?php
 3+
 4+/** Armenian (Հայերեն)
 5+ *
 6+ * @ingroup Language
 7+ * @author Ruben Vardanyan (Me@RubenVardanyan.com)
 8+ */
 9+class LanguageHy extends Language {
 10+
 11+ /**
 12+ * Convert from the nominative form of a noun to some other case
 13+ * Invoked with {{grammar:case|word}}
 14+ *
 15+ * @param $word string
 16+ * @param $case string
 17+ * @return string
 18+ */
 19+ function convertGrammar( $word, $case ) {
 20+ global $wgGrammarForms;
 21+ if ( isset( $wgGrammarForms['hy'][$case][$word] ) ) {
 22+ return $wgGrammarForms['hy'][$case][$word];
 23+ }
 24+
 25+ # These rules are not perfect, but they are currently only used for site names so it doesn't
 26+ # matter if they are wrong sometimes. Just add a special case for your site name if necessary.
 27+
 28+ # join and array_slice instead mb_substr
 29+ $ar = array();
 30+ preg_match_all( '/./us', $word, $ar );
 31+ if ( !preg_match( "/[a-zA-Z_]/us", $word ) )
 32+ switch ( $case ) {
 33+ case 'genitive': # սեռական հոլով
 34+ if ( join( '', array_slice( $ar[0], -1 ) ) == 'ա' )
 35+ $word = join( '', array_slice( $ar[0], 0, -1 ) ) . 'այի';
 36+ elseif ( join( '', array_slice( $ar[0], -1 ) ) == 'ո' )
 37+ $word = join( '', array_slice( $ar[0], 0, -1 ) ) . 'ոյի';
 38+ elseif ( join( '', array_slice( $ar[0], -4 ) ) == 'գիրք' )
 39+ $word = join( '', array_slice( $ar[0], 0, -4 ) ) . 'գրքի';
 40+ else
 41+ $word .= 'ի';
 42+ break;
 43+ case 'dative': # Տրական հոլով
 44+ # stub
 45+ break;
 46+ case 'accusative': # Հայցական հոլով
 47+ # stub
 48+ break;
 49+ case 'instrumental': #
 50+ # stub
 51+ break;
 52+ case 'prepositional': #
 53+ # stub
 54+ break;
 55+ }
 56+ return $word;
 57+ }
 58+
 59+ /**
 60+ * @param $count int
 61+ * @param $forms array
 62+ *
 63+ * @return string
 64+ */
 65+ function convertPlural( $count, $forms ) {
 66+ if ( !count( $forms ) ) { return ''; }
 67+ $forms = $this->preConvertPlural( $forms, 2 );
 68+
 69+ return ( abs( $count ) <= 1 ) ? $forms[0] : $forms[1];
 70+ }
 71+
 72+ /**
 73+ * Armenian numeric format is "12 345,67" but "1234,56"
 74+ *
 75+ * @param $_ string
 76+ *
 77+ * @return string
 78+ */
 79+ function commafy( $_ ) {
 80+ if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
 81+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 82+ } else {
 83+ return $_;
 84+ }
 85+ }
 86+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageHy.php
___________________________________________________________________
Added: svn:eol-style
187 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageLv.php
@@ -0,0 +1,31 @@
 2+<?php
 3+
 4+/** Latvian (Latviešu)
 5+ *
 6+ * @ingroup Language
 7+ *
 8+ * @author Niklas Laxström
 9+ *
 10+ * @copyright Copyright © 2006, Niklas Laxström
 11+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 12+ */
 13+class LanguageLv extends Language {
 14+ /**
 15+ * Plural form transformations. Using the first form for words with the last digit 1, but not for words with the last digits 11, and the second form for all the others.
 16+ *
 17+ * Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}}
 18+ *
 19+ * @param $count Integer
 20+ * @param $forms Array
 21+ * @return String
 22+ */
 23+ function convertPlural( $count, $forms ) {
 24+ if ( !count( $forms ) ) { return ''; }
 25+
 26+ // @todo FIXME: CLDR defines 3 plural forms instead of 2. Form for 0 is missing.
 27+ // http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#lv
 28+ $forms = $this->preConvertPlural( $forms, 2 );
 29+
 30+ return ( ( $count % 10 == 1 ) && ( $count % 100 != 11 ) ) ? $forms[0] : $forms[1];
 31+ }
 32+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageLv.php
___________________________________________________________________
Added: svn:eol-style
133 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageKsh.php
@@ -0,0 +1,182 @@
 2+<?php
 3+
 4+/** Ripuarian (Ripoarėsh)
 5+ *
 6+ * @ingroup Language
 7+ *
 8+ * @author Purodha Blissenbach
 9+ */
 10+class LanguageKsh extends Language {
 11+ static $familygender = array(
 12+ // Do not add male wiki families, since that's the default.
 13+ // No need add neuter wikis having names ending in -wiki.
 14+ 'wikipedia' => 'f',
 15+ 'wikiversity' => 'f',
 16+ 'wiktionary' => 'n',
 17+ 'wikibooks' => 'n',
 18+ 'wikiquote' => 'n',
 19+ 'wikisource' => 'n',
 20+ 'wikitravel' => 'n',
 21+ 'wikia' => 'f',
 22+ 'translatewiki.net' => 'n',
 23+ );
 24+
 25+ /**
 26+ * Convert from the nominative form of a noun to other cases.
 27+ * Invoked with {{GRAMMAR:case|word}} inside messages.
 28+ *
 29+ * case is a sequence of words, each of which is case insensitive.
 30+ * Between words, there must be at least one space character.
 31+ * Only the 1st character of each word is considered.
 32+ * Word order is irrelevant.
 33+ *
 34+ * Possible values specifying the grammatical case are:
 35+ * 1, Nominative
 36+ * 2, Genitive
 37+ * 3, Dative
 38+ * 4, Accusative, -omitted-
 39+ *
 40+ * Possible values specifying the article type are:
 41+ * Betoont focussed or stressed article
 42+ * -omitted- unstressed or unfocussed article
 43+ *
 44+ * Possible values for the type of genitive are:
 45+ * Sing, Iehr prepositioned genitive = possessive dative
 46+ * Vun, Fon, -omitted- postpositioned genitive
 47+ * = preposition "vun" with dative
 48+ *
 49+ * Values of case overrides & prepositions, in the order of preceedence:
 50+ * Sing, Iehr possessive dative = prepositioned genitive
 51+ * Vun, Fon preposition "vun" with dative
 52+ * = postpositioned genitive
 53+ * En, em preposition "en" with dative
 54+ *
 55+ * Values for object gender specifiers of the possessive dative, or
 56+ * prepositioned genitive, evaluated with "Sing, Iehr" of above only:
 57+ * Male a singular male object follows
 58+ * -omitted- a non-male or plural object follows
 59+ *
 60+ * We currently handle definite articles of the singular only.
 61+ * There is a full set of test cases at:
 62+ * http://translatewiki.net/wiki/Portal:Ksh#GRAMMAR_Pr%C3%B6%C3%B6fe
 63+ * Contents of the leftmost table column can be copied and pasted as
 64+ * "case" values.
 65+ *
 66+ * @param $word String
 67+ * @param $case String
 68+ *
 69+ * @return string
 70+ */
 71+ function convertGrammar( $word, $case ) {
 72+ $lord = strtolower( $word );
 73+ $gender = 'm'; // Nuutnaarel // default
 74+ if ( preg_match ( '/wiki$/', $lord ) ) {
 75+ $gender = 'n'; // Dat xyz-wiki
 76+ }
 77+ if ( isset( self::$familygender[$lord] ) ) {
 78+ $gender = self::$familygender[$lord];
 79+ }
 80+ $case = ' ' . strtolower( $case );
 81+ if ( preg_match( '/ [is]/', $case ) ) {
 82+ # däm WikiMaatplaz singe, dä Wikipeedija iere, däm Wikiwööterbooch singe
 83+ # dem/em WikiMaatplaz singe, de Wikipeedija iere, dem/em Wikiwööterbooch singe
 84+ # däm WikiMaatplaz sing, dä Wikipeedija ier, däm Wikiwööterbooch sing
 85+ # dem/em WikiMaatplaz sing, de Wikipeedija ier, dem/em Wikiwööterbooch sing
 86+ $word = ( preg_match( '/ b/', $case )
 87+ ? ( $gender=='f' ? 'dä' : 'däm' )
 88+ : ( $gender=='f' ? 'de' : 'dem' )
 89+ ) . ' ' . $word . ' ' .
 90+ ( $gender=='f' ? 'ier' : 'sing' ) .
 91+ ( preg_match( '/ m/', $case ) ? 'e' : ''
 92+ );
 93+ } elseif ( preg_match( '/ e/', $case ) ) {
 94+ # en dämm WikiMaatPlaz, en dä Wikipeedija, en dämm Wikiwööterbooch
 95+ # em WikiMaatplaz, en de Wikipeedija, em Wikiwööterbooch
 96+ if ( preg_match( '/ b/', $case ) ) {
 97+ $word = 'en '.( $gender == 'f' ? 'dä' : 'däm' ) . ' ' . $word;
 98+ } else {
 99+ $word = ( $gender == 'f' ? 'en de' : 'em' ) . ' ' . $word;
 100+ }
 101+ } elseif ( preg_match( '/ [fv]/', $case ) || preg_match( '/ [2jg]/', $case ) ) {
 102+ # vun däm WikiMaatplaz, vun dä Wikipeedija, vun däm Wikiwööterbooch
 103+ # vum WikiMaatplaz, vun de Wikipeedija, vum Wikiwööterbooch
 104+ if ( preg_match( '/ b/', $case ) ) {
 105+ $word = 'vun ' . ( $gender == 'f' ? 'dä' : 'däm' ) . ' ' . $word;
 106+ } else {
 107+ $word = ( $gender== 'f' ? 'vun de' : 'vum' ) . ' ' . $word;
 108+ }
 109+ } elseif ( preg_match( '/ [3d]/', $case ) ) {
 110+ # dämm WikiMaatPlaz, dä Wikipeedija, dämm Wikiwööterbooch
 111+ # dem/em WikiMaatplaz, de Wikipeedija, dem/em Wikiwööterbooch
 112+ if ( preg_match( '/ b/', $case ) ) {
 113+ $word = ( $gender == 'f' ? 'dää' : 'dämm' ) .' ' . $word;
 114+ } else {
 115+ $word = ( $gender == 'f' ? 'de' : 'dem' ) . ' ' . $word;
 116+ }
 117+ } else {
 118+ # dä WikiMaatPlaz, di Wikipeedija, dat Wikiwööterbooch
 119+ # der WikiMaatplaz, de Wikipeedija, et Wikiwööterbooch
 120+ if ( preg_match( '/ b/', $case ) ) {
 121+ switch ( $gender ) {
 122+ case 'm':
 123+ $lord = 'dä';
 124+ break ;
 125+ case 'f':
 126+ $lord = 'di';
 127+ break;
 128+ default:
 129+ $lord = 'dat';
 130+ }
 131+ } else {
 132+ switch ( $gender ) {
 133+ case 'm':
 134+ $lord = 'der';
 135+ break;
 136+ case 'f':
 137+ $lord = 'de';
 138+ break;
 139+ default:
 140+ $lord = 'et';
 141+ }
 142+ }
 143+ $word = $lord.' '.$word;
 144+ }
 145+ return $word;
 146+ }
 147+
 148+ /**
 149+ * Avoid grouping whole numbers between 0 to 9999
 150+ *
 151+ * @param $_ string
 152+ *
 153+ * @return string
 154+ */
 155+ public function commafy( $_ ) {
 156+ if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
 157+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 158+ } else {
 159+ return $_;
 160+ }
 161+ }
 162+
 163+ /**
 164+ * Handle cases of (1, other, 0) or (1, other)
 165+ *
 166+ * @param $count int
 167+ * @param $forms array
 168+ *
 169+ * @return string
 170+ */
 171+ function convertPlural( $count, $forms ) {
 172+ if ( !count( $forms ) ) { return ''; }
 173+ $forms = $this->preConvertPlural( $forms, 3 );
 174+
 175+ if ( $count == 1 ) {
 176+ return $forms[0];
 177+ } elseif ( $count == 0 ) {
 178+ return $forms[2];
 179+ } else {
 180+ return $forms[1];
 181+ }
 182+ }
 183+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageKsh.php
___________________________________________________________________
Added: svn:eol-style
1184 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageTr.php
@@ -0,0 +1,65 @@
 2+<?php
 3+
 4+/**
 5+ * Turkish (Türkçe)
 6+ *
 7+ * Turkish has two different i, one with a dot and another without a dot. They
 8+ * are totally different letters in this language, so we have to override the
 9+ * ucfirst and lcfirst methods.
 10+ * See http://en.wikipedia.org/wiki/Dotted_and_dotless_I
 11+ * and @bug 28040
 12+ * @ingroup Language
 13+ */
 14+class LanguageTr extends Language {
 15+
 16+ /**
 17+ * @param $string string
 18+ * @return string
 19+ */
 20+ function ucfirst ( $string ) {
 21+ if ( !empty( $string ) && $string[0] == 'i' ) {
 22+ return 'İ' . substr( $string, 1 );
 23+ } else {
 24+ return parent::ucfirst( $string );
 25+ }
 26+ }
 27+
 28+ /**
 29+ * @param $string string
 30+ * @return mixed|string
 31+ */
 32+ function lcfirst ( $string ) {
 33+ if ( !empty( $string ) && $string[0] == 'I' ) {
 34+ return 'ı' . substr( $string, 1 );
 35+ } else {
 36+ return parent::lcfirst( $string );
 37+ }
 38+ }
 39+
 40+ /**
 41+ * @see bug 28040
 42+ *
 43+ * @param $string string
 44+ * @param $first string|bool
 45+ *
 46+ * @return string
 47+ */
 48+ function uc( $string, $first = false ) {
 49+ $string = preg_replace( '/i/', 'İ', $string );
 50+ return parent::uc( $string, $first );
 51+ }
 52+
 53+ /**
 54+ * @see bug 28040
 55+ *
 56+ * @param $string string
 57+ * @param $first string|bool
 58+ *
 59+ * @return string
 60+ */
 61+ function lc( $string, $first = false ) {
 62+ $string = preg_replace( '/I/', 'ı', $string );
 63+ return parent::lc( $string, $first );
 64+ }
 65+
 66+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageTr.php
___________________________________________________________________
Added: svn:eol-style
167 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageZh_hans.php
@@ -0,0 +1,47 @@
 2+<?php
 3+
 4+/**
 5+ * Simplified Chinese
 6+ *
 7+ * @ingroup Language
 8+ */
 9+class LanguageZh_hans extends Language {
 10+
 11+ /**
 12+ * @return bool
 13+ */
 14+ function hasWordBreaks() {
 15+ return false;
 16+ }
 17+
 18+ /**
 19+ * Eventually this should be a word segmentation;
 20+ * for now just treat each character as a word.
 21+ * @todo FIXME: Only do this for Han characters...
 22+ *
 23+ * @param $string string
 24+ *
 25+ * @return string
 26+ */
 27+ function segmentByWord( $string ) {
 28+ $reg = "/([\\xc0-\\xff][\\x80-\\xbf]*)/";
 29+ $s = self::insertSpace( $string, $reg );
 30+ return $s;
 31+ }
 32+
 33+ /**
 34+ * @param $s
 35+ * @return string
 36+ */
 37+ function normalizeForSearch( $s ) {
 38+ wfProfileIn( __METHOD__ );
 39+
 40+ // Double-width roman characters
 41+ $s = parent::normalizeForSearch( $s );
 42+ $s = trim( $s );
 43+ $s = $this->segmentByWord( $s );
 44+
 45+ wfProfileOut( __METHOD__ );
 46+ return $s;
 47+ }
 48+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageZh_hans.php
___________________________________________________________________
Added: svn:eol-style
149 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSgs.php
@@ -0,0 +1,30 @@
 2+<?php
 3+/** Samogitian (Žemaitėška)
 4+ *
 5+ * @ingroup Language
 6+ *
 7+ * @author Niklas Laxström
 8+ */
 9+class LanguageSgs extends Language {
 10+
 11+ /**
 12+ * @param $count int
 13+ * @param $forms array
 14+ * @return string
 15+ */
 16+ function convertPlural( $count, $forms ) {
 17+ if ( !count( $forms ) ) { return ''; }
 18+ $forms = $this->preConvertPlural( $forms, 4 );
 19+
 20+ $count = abs( $count );
 21+ if ( $count === 0 || ( $count % 100 === 0 || ( $count % 100 >= 10 && $count % 100 < 20 ) ) ) {
 22+ return $forms[2];
 23+ } elseif ( $count % 10 === 1 ) {
 24+ return $forms[0];
 25+ } elseif ( $count % 10 === 2 ) {
 26+ return $forms[1];
 27+ } else {
 28+ return $forms[3];
 29+ }
 30+ }
 31+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSgs.php
___________________________________________________________________
Added: svn:eol-style
132 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageAm.php
@@ -0,0 +1,22 @@
 2+<?php
 3+/**
 4+ * Amharic (አማርኛ)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageAm extends Language {
 9+ /**
 10+ * Use singular form for zero
 11+ *
 12+ * @param $count int
 13+ * @param $forms array
 14+ *
 15+ * @return string
 16+ */
 17+ function convertPlural( $count, $forms ) {
 18+ if ( !count( $forms ) ) { return ''; }
 19+ $forms = $this->preConvertPlural( $forms, 2 );
 20+
 21+ return ( $count <= 1 ) ? $forms[0] : $forms[1];
 22+ }
 23+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageAm.php
___________________________________________________________________
Added: svn:eol-style
124 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSr_el.deps.php
@@ -0,0 +1,8 @@
 2+<?php
 3+// This file exists to ensure that base classes are preloaded before
 4+// LanguageSr_el.php is compiled, working around a bug in the APC opcode
 5+// cache on PHP 5, where cached code can break if the include order
 6+// changed on a subsequent page view.
 7+// see http://mail.wikipedia.org/pipermail/wikitech-l/2006-January/033660.html
 8+
 9+require_once( dirname( __FILE__ ) . '/LanguageSr_ec.php' );
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSr_el.deps.php
___________________________________________________________________
Added: svn:eol-style
110 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageAr.php
@@ -0,0 +1,54 @@
 2+<?php
 3+/** Arabic (العربية)
 4+ *
 5+ * @ingroup Language
 6+ *
 7+ * @author Niklas Laxström
 8+ */
 9+class LanguageAr extends Language {
 10+
 11+ /**
 12+ * @param $count int
 13+ * @param $forms array
 14+ * @return string
 15+ */
 16+ function convertPlural( $count, $forms ) {
 17+ if ( !count( $forms ) ) { return ''; }
 18+ $forms = $this->preConvertPlural( $forms, 6 );
 19+
 20+ if ( $count == 0 ) {
 21+ $index = 0;
 22+ } elseif ( $count == 1 ) {
 23+ $index = 1;
 24+ } elseif ( $count == 2 ) {
 25+ $index = 2;
 26+ } elseif ( $count % 100 >= 3 && $count % 100 <= 10 ) {
 27+ $index = 3;
 28+ } elseif ( $count % 100 >= 11 && $count % 100 <= 99 ) {
 29+ $index = 4;
 30+ } else {
 31+ $index = 5;
 32+ }
 33+ return $forms[$index];
 34+ }
 35+
 36+ /**
 37+ * Temporary hack for bug 9413: replace Arabic presentation forms with their
 38+ * standard equivalents.
 39+ *
 40+ * @todo FIXME: This is language-specific for now only to avoid the negative
 41+ * performance impact of enabling it for all languages.
 42+ *
 43+ * @param $s string
 44+ *
 45+ * @return string
 46+ */
 47+ function normalize( $s ) {
 48+ global $wgFixArabicUnicode;
 49+ $s = parent::normalize( $s );
 50+ if ( $wgFixArabicUnicode ) {
 51+ $s = $this->transformUsingPairFile( 'normalize-ar.ser', $s );
 52+ }
 53+ return $s;
 54+ }
 55+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageAr.php
___________________________________________________________________
Added: svn:eol-style
156 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageMg.php
@@ -0,0 +1,22 @@
 2+<?php
 3+/**
 4+ * Malagasy (Malagasy)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageMg extends Language {
 9+ /**
 10+ * Use singular form for zero
 11+ *
 12+ * @param $count int
 13+ * @param $forms array
 14+ *
 15+ * @return string
 16+ */
 17+ function convertPlural( $count, $forms ) {
 18+ if ( !count( $forms ) ) { return ''; }
 19+ $forms = $this->preConvertPlural( $forms, 2 );
 20+
 21+ return ( $count <= 1 ) ? $forms[0] : $forms[1];
 22+ }
 23+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageMg.php
___________________________________________________________________
Added: svn:eol-style
124 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageEo.php
@@ -0,0 +1,123 @@
 2+<?php
 3+
 4+/** Esperanto (Esperanto)
 5+ *
 6+ * @ingroup Language
 7+ * @author Brion Vibber <brion@pobox.com>
 8+ */
 9+class LanguageEo extends Language {
 10+ /**
 11+ * Wrapper for charset conversions.
 12+ *
 13+ * In most languages, this calls through to standard system iconv(), but
 14+ * for Esperanto we're also adding a special pseudo-charset to convert
 15+ * accented characters to/from the ASCII-friendly "X" surrogate coding:
 16+ *
 17+ * cx = ĉ cxx = cx
 18+ * gx = ĝ gxx = gx
 19+ * hx = ĥ hxx = hx
 20+ * jx = ĵ jxx = jx
 21+ * sx = ŝ sxx = sx
 22+ * ux = ŭ uxx = ux
 23+ * xx = x
 24+ *
 25+ * http://en.wikipedia.org/wiki/Esperanto_orthography#X-system
 26+ * http://eo.wikipedia.org/wiki/X-sistemo
 27+ *
 28+ * X-conversion is applied, in either direction, between "utf-8" and "x" charsets;
 29+ * this comes into effect when input is run through $wgRequest->getText() and the
 30+ * $wgEditEncoding is set to 'x'.
 31+ *
 32+ * In the long run, this should be moved out of here and into the client-side
 33+ * editor behavior; the original server-side translation system dates to 2002-2003
 34+ * when many browsers with really bad Unicode support were still in use.
 35+ *
 36+ * @param string $in input character set
 37+ * @param string $out output character set
 38+ * @param string $string text to be converted
 39+ * @return string
 40+ */
 41+ function iconv( $in, $out, $string ) {
 42+ if ( strcasecmp( $in, 'x' ) == 0 && strcasecmp( $out, 'utf-8' ) == 0 ) {
 43+ return preg_replace_callback (
 44+ '/([cghjsu]x?)((?:xx)*)(?!x)/i',
 45+ array( $this, 'strrtxuCallback' ), $string );
 46+ } elseif ( strcasecmp( $in, 'UTF-8' ) == 0 && strcasecmp( $out, 'x' ) == 0 ) {
 47+ # Double Xs only if they follow cxapelutaj literoj.
 48+ return preg_replace_callback(
 49+ '/((?:[cghjsu]|\xc4[\x88\x89\x9c\x9d\xa4\xa5\xb4\xb5]|\xc5[\x9c\x9d\xac\xad])x*)/i',
 50+ array( $this, 'strrtuxCallback' ), $string );
 51+ }
 52+ return parent::iconv( $in, $out, $string );
 53+ }
 54+
 55+ /**
 56+ * @param $matches array
 57+ * @return string
 58+ */
 59+ function strrtuxCallback( $matches ) {
 60+ static $ux = array (
 61+ 'x' => 'xx' , 'X' => 'Xx' ,
 62+ "\xc4\x88" => "Cx" , "\xc4\x89" => "cx" ,
 63+ "\xc4\x9c" => "Gx" , "\xc4\x9d" => "gx" ,
 64+ "\xc4\xa4" => "Hx" , "\xc4\xa5" => "hx" ,
 65+ "\xc4\xb4" => "Jx" , "\xc4\xb5" => "jx" ,
 66+ "\xc5\x9c" => "Sx" , "\xc5\x9d" => "sx" ,
 67+ "\xc5\xac" => "Ux" , "\xc5\xad" => "ux"
 68+ );
 69+ return strtr( $matches[1], $ux );
 70+ }
 71+
 72+ /**
 73+ * @param $matches array
 74+ * @return string
 75+ */
 76+ function strrtxuCallback( $matches ) {
 77+ static $xu = array (
 78+ 'xx' => 'x' , 'xX' => 'x' ,
 79+ 'Xx' => 'X' , 'XX' => 'X' ,
 80+ "Cx" => "\xc4\x88" , "CX" => "\xc4\x88" ,
 81+ "cx" => "\xc4\x89" , "cX" => "\xc4\x89" ,
 82+ "Gx" => "\xc4\x9c" , "GX" => "\xc4\x9c" ,
 83+ "gx" => "\xc4\x9d" , "gX" => "\xc4\x9d" ,
 84+ "Hx" => "\xc4\xa4" , "HX" => "\xc4\xa4" ,
 85+ "hx" => "\xc4\xa5" , "hX" => "\xc4\xa5" ,
 86+ "Jx" => "\xc4\xb4" , "JX" => "\xc4\xb4" ,
 87+ "jx" => "\xc4\xb5" , "jX" => "\xc4\xb5" ,
 88+ "Sx" => "\xc5\x9c" , "SX" => "\xc5\x9c" ,
 89+ "sx" => "\xc5\x9d" , "sX" => "\xc5\x9d" ,
 90+ "Ux" => "\xc5\xac" , "UX" => "\xc5\xac" ,
 91+ "ux" => "\xc5\xad" , "uX" => "\xc5\xad"
 92+ );
 93+ return strtr( $matches[1], $xu ) . strtr( $matches[2], $xu );
 94+ }
 95+
 96+ /**
 97+ * @param $s string
 98+ * @return string
 99+ */
 100+ function checkTitleEncoding( $s ) {
 101+ # Check for X-system backwards-compatibility URLs
 102+ $ishigh = preg_match( '/[\x80-\xff]/', $s );
 103+ $isutf = preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
 104+ '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
 105+
 106+ if ( $ishigh and !$isutf ) {
 107+ # Assume Latin1
 108+ $s = utf8_encode( $s );
 109+ } else {
 110+ if ( preg_match( '/(\xc4[\x88\x89\x9c\x9d\xa4\xa5\xb4\xb5]' .
 111+ '|\xc5[\x9c\x9d\xac\xad])/', $s ) )
 112+ return $s;
 113+ }
 114+
 115+ // if( preg_match( '/[cghjsu]x/i', $s ) )
 116+ // return $this->iconv( 'x', 'utf-8', $s );
 117+ return $s;
 118+ }
 119+
 120+ function initEncoding() {
 121+ global $wgEditEncoding;
 122+ $wgEditEncoding = 'x';
 123+ }
 124+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageEo.php
___________________________________________________________________
Added: svn:eol-style
1125 + native
Index: trunk/tools/ToolserverI18N/language/classes/LICENSE.txt
@@ -0,0 +1,345 @@
 2+This directory is a copy of the languages/classes directory of MediaWiki. The files are under the "GNU GENERAL PUBLIC LICENSE Version 2" (see below).
 3+
 4+
 5+== GNU GENERAL PUBLIC LICENSE ==
 6+
 7+Version 2, June 1991
 8+
 9+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 10+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 11+Everyone is permitted to copy and distribute verbatim copies
 12+of this license document, but changing it is not allowed.
 13+
 14+=== Preamble ===
 15+
 16+The licenses for most software are designed to take away your
 17+freedom to share and change it. By contrast, the GNU General Public
 18+License is intended to guarantee your freedom to share and change free
 19+software--to make sure the software is free for all its users. This
 20+General Public License applies to most of the Free Software
 21+Foundation's software and to any other program whose authors commit to
 22+using it. (Some other Free Software Foundation software is covered by
 23+the GNU Library General Public License instead.) You can apply it to
 24+your programs, too.
 25+
 26+When we speak of free software, we are referring to freedom, not
 27+price. Our General Public Licenses are designed to make sure that you
 28+have the freedom to distribute copies of free software (and charge for
 29+this service if you wish), that you receive source code or can get it
 30+if you want it, that you can change the software or use pieces of it
 31+in new free programs; and that you know you can do these things.
 32+
 33+To protect your rights, we need to make restrictions that forbid
 34+anyone to deny you these rights or to ask you to surrender the rights.
 35+These restrictions translate to certain responsibilities for you if you
 36+distribute copies of the software, or if you modify it.
 37+
 38+For example, if you distribute copies of such a program, whether
 39+gratis or for a fee, you must give the recipients all the rights that
 40+you have. You must make sure that they, too, receive or can get the
 41+source code. And you must show them these terms so they know their
 42+rights.
 43+
 44+We protect your rights with two steps: (1) copyright the software, and
 45+(2) offer you this license which gives you legal permission to copy,
 46+distribute and/or modify the software.
 47+
 48+Also, for each author's protection and ours, we want to make certain
 49+that everyone understands that there is no warranty for this free
 50+software. If the software is modified by someone else and passed on, we
 51+want its recipients to know that what they have is not the original, so
 52+that any problems introduced by others will not reflect on the original
 53+authors' reputations.
 54+
 55+Finally, any free program is threatened constantly by software
 56+patents. We wish to avoid the danger that redistributors of a free
 57+program will individually obtain patent licenses, in effect making the
 58+program proprietary. To prevent this, we have made it clear that any
 59+patent must be licensed for everyone's free use or not licensed at all.
 60+
 61+The precise terms and conditions for copying, distribution and
 62+modification follow.
 63+
 64+== TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ==
 65+
 66+'''0.''' This License applies to any program or other work which contains
 67+a notice placed by the copyright holder saying it may be distributed
 68+under the terms of this General Public License. The "Program", below,
 69+refers to any such program or work, and a "work based on the Program"
 70+means either the Program or any derivative work under copyright law:
 71+that is to say, a work containing the Program or a portion of it,
 72+either verbatim or with modifications and/or translated into another
 73+language. (Hereinafter, translation is included without limitation in
 74+the term "modification".) Each licensee is addressed as "you".
 75+
 76+Activities other than copying, distribution and modification are not
 77+covered by this License; they are outside its scope. The act of
 78+running the Program is not restricted, and the output from the Program
 79+is covered only if its contents constitute a work based on the
 80+Program (independent of having been made by running the Program).
 81+Whether that is true depends on what the Program does.
 82+
 83+'''1.''' You may copy and distribute verbatim copies of the Program's
 84+source code as you receive it, in any medium, provided that you
 85+conspicuously and appropriately publish on each copy an appropriate
 86+copyright notice and disclaimer of warranty; keep intact all the
 87+notices that refer to this License and to the absence of any warranty;
 88+and give any other recipients of the Program a copy of this License
 89+along with the Program.
 90+
 91+You may charge a fee for the physical act of transferring a copy, and
 92+you may at your option offer warranty protection in exchange for a fee.
 93+
 94+'''2.''' You may modify your copy or copies of the Program or any portion
 95+of it, thus forming a work based on the Program, and copy and
 96+distribute such modifications or work under the terms of Section 1
 97+above, provided that you also meet all of these conditions:
 98+
 99+ '''a)''' You must cause the modified files to carry prominent notices
 100+ stating that you changed the files and the date of any change.
 101+
 102+ '''b)''' You must cause any work that you distribute or publish, that in
 103+ whole or in part contains or is derived from the Program or any
 104+ part thereof, to be licensed as a whole at no charge to all third
 105+ parties under the terms of this License.
 106+
 107+ '''c)''' If the modified program normally reads commands interactively
 108+ when run, you must cause it, when started running for such
 109+ interactive use in the most ordinary way, to print or display an
 110+ announcement including an appropriate copyright notice and a
 111+ notice that there is no warranty (or else, saying that you provide
 112+ a warranty) and that users may redistribute the program under
 113+ these conditions, and telling the user how to view a copy of this
 114+ License. (Exception: if the Program itself is interactive but
 115+ does not normally print such an announcement, your work based on
 116+ the Program is not required to print an announcement.)
 117+
 118+These requirements apply to the modified work as a whole. If
 119+identifiable sections of that work are not derived from the Program,
 120+and can be reasonably considered independent and separate works in
 121+themselves, then this License, and its terms, do not apply to those
 122+sections when you distribute them as separate works. But when you
 123+distribute the same sections as part of a whole which is a work based
 124+on the Program, the distribution of the whole must be on the terms of
 125+this License, whose permissions for other licensees extend to the
 126+entire whole, and thus to each and every part regardless of who wrote it.
 127+
 128+Thus, it is not the intent of this section to claim rights or contest
 129+your rights to work written entirely by you; rather, the intent is to
 130+exercise the right to control the distribution of derivative or
 131+collective works based on the Program.
 132+
 133+In addition, mere aggregation of another work not based on the Program
 134+with the Program (or with a work based on the Program) on a volume of
 135+a storage or distribution medium does not bring the other work under
 136+the scope of this License.
 137+
 138+'''3.''' You may copy and distribute the Program (or a work based on it,
 139+under Section 2) in object code or executable form under the terms of
 140+Sections 1 and 2 above provided that you also do one of the following:
 141+
 142+ '''a)''' Accompany it with the complete corresponding machine-readable
 143+ source code, which must be distributed under the terms of Sections
 144+ 1 and 2 above on a medium customarily used for software interchange; or,
 145+
 146+ '''b)''' Accompany it with a written offer, valid for at least three
 147+ years, to give any third party, for a charge no more than your
 148+ cost of physically performing source distribution, a complete
 149+ machine-readable copy of the corresponding source code, to be
 150+ distributed under the terms of Sections 1 and 2 above on a medium
 151+ customarily used for software interchange; or,
 152+
 153+ '''c)''' Accompany it with the information you received as to the offer
 154+ to distribute corresponding source code. (This alternative is
 155+ allowed only for noncommercial distribution and only if you
 156+ received the program in object code or executable form with such
 157+ an offer, in accord with Subsection b above.)
 158+
 159+The source code for a work means the preferred form of the work for
 160+making modifications to it. For an executable work, complete source
 161+code means all the source code for all modules it contains, plus any
 162+associated interface definition files, plus the scripts used to
 163+control compilation and installation of the executable. However, as a
 164+special exception, the source code distributed need not include
 165+anything that is normally distributed (in either source or binary
 166+form) with the major components (compiler, kernel, and so on) of the
 167+operating system on which the executable runs, unless that component
 168+itself accompanies the executable.
 169+
 170+If distribution of executable or object code is made by offering
 171+access to copy from a designated place, then offering equivalent
 172+access to copy the source code from the same place counts as
 173+distribution of the source code, even though third parties are not
 174+compelled to copy the source along with the object code.
 175+
 176+'''4.''' You may not copy, modify, sublicense, or distribute the Program
 177+except as expressly provided under this License. Any attempt
 178+otherwise to copy, modify, sublicense or distribute the Program is
 179+void, and will automatically terminate your rights under this License.
 180+However, parties who have received copies, or rights, from you under
 181+this License will not have their licenses terminated so long as such
 182+parties remain in full compliance.
 183+
 184+'''5.''' You are not required to accept this License, since you have not
 185+signed it. However, nothing else grants you permission to modify or
 186+distribute the Program or its derivative works. These actions are
 187+prohibited by law if you do not accept this License. Therefore, by
 188+modifying or distributing the Program (or any work based on the
 189+Program), you indicate your acceptance of this License to do so, and
 190+all its terms and conditions for copying, distributing or modifying
 191+the Program or works based on it.
 192+
 193+'''6.''' Each time you redistribute the Program (or any work based on the
 194+Program), the recipient automatically receives a license from the
 195+original licensor to copy, distribute or modify the Program subject to
 196+these terms and conditions. You may not impose any further
 197+restrictions on the recipients' exercise of the rights granted herein.
 198+You are not responsible for enforcing compliance by third parties to
 199+this License.
 200+
 201+'''7.''' If, as a consequence of a court judgment or allegation of patent
 202+infringement or for any other reason (not limited to patent issues),
 203+conditions are imposed on you (whether by court order, agreement or
 204+otherwise) that contradict the conditions of this License, they do not
 205+excuse you from the conditions of this License. If you cannot
 206+distribute so as to satisfy simultaneously your obligations under this
 207+License and any other pertinent obligations, then as a consequence you
 208+may not distribute the Program at all. For example, if a patent
 209+license would not permit royalty-free redistribution of the Program by
 210+all those who receive copies directly or indirectly through you, then
 211+the only way you could satisfy both it and this License would be to
 212+refrain entirely from distribution of the Program.
 213+
 214+If any portion of this section is held invalid or unenforceable under
 215+any particular circumstance, the balance of the section is intended to
 216+apply and the section as a whole is intended to apply in other
 217+circumstances.
 218+
 219+It is not the purpose of this section to induce you to infringe any
 220+patents or other property right claims or to contest validity of any
 221+such claims; this section has the sole purpose of protecting the
 222+integrity of the free software distribution system, which is
 223+implemented by public license practices. Many people have made
 224+generous contributions to the wide range of software distributed
 225+through that system in reliance on consistent application of that
 226+system; it is up to the author/donor to decide if he or she is willing
 227+to distribute software through any other system and a licensee cannot
 228+impose that choice.
 229+
 230+This section is intended to make thoroughly clear what is believed to
 231+be a consequence of the rest of this License.
 232+
 233+'''8.''' If the distribution and/or use of the Program is restricted in
 234+certain countries either by patents or by copyrighted interfaces, the
 235+original copyright holder who places the Program under this License
 236+may add an explicit geographical distribution limitation excluding
 237+those countries, so that distribution is permitted only in or among
 238+countries not thus excluded. In such case, this License incorporates
 239+the limitation as if written in the body of this License.
 240+
 241+'''9.''' The Free Software Foundation may publish revised and/or new versions
 242+of the General Public License from time to time. Such new versions will
 243+be similar in spirit to the present version, but may differ in detail to
 244+address new problems or concerns.
 245+
 246+Each version is given a distinguishing version number. If the Program
 247+specifies a version number of this License which applies to it and "any
 248+later version", you have the option of following the terms and conditions
 249+either of that version or of any later version published by the Free
 250+Software Foundation. If the Program does not specify a version number of
 251+this License, you may choose any version ever published by the Free Software
 252+Foundation.
 253+
 254+'''10.''' If you wish to incorporate parts of the Program into other free
 255+programs whose distribution conditions are different, write to the author
 256+to ask for permission. For software which is copyrighted by the Free
 257+Software Foundation, write to the Free Software Foundation; we sometimes
 258+make exceptions for this. Our decision will be guided by the two goals
 259+of preserving the free status of all derivatives of our free software and
 260+of promoting the sharing and reuse of software generally.
 261+
 262+=== NO WARRANTY ===
 263+
 264+'''11.''' BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 265+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
 266+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 267+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 268+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 269+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
 270+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
 271+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 272+REPAIR OR CORRECTION.
 273+
 274+'''12.''' IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 275+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 276+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
 277+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
 278+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
 279+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
 280+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 281+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 282+POSSIBILITY OF SUCH DAMAGES.
 283+
 284+ '''END OF TERMS AND CONDITIONS'''
 285+
 286+== How to Apply These Terms to Your New Programs ==
 287+
 288+If you develop a new program, and you want it to be of the greatest
 289+possible use to the public, the best way to achieve this is to make it
 290+free software which everyone can redistribute and change under these terms.
 291+
 292+To do so, attach the following notices to the program. It is safest
 293+to attach them to the start of each source file to most effectively
 294+convey the exclusion of warranty; and each file should have at least
 295+the "copyright" line and a pointer to where the full notice is found.
 296+
 297+ <one line to give the program's name and a brief idea of what it does.>
 298+
 299+ Copyright (C) <year> <name of author>
 300+
 301+ This program is free software; you can redistribute it and/or modify
 302+ it under the terms of the GNU General Public License as published by
 303+ the Free Software Foundation; either version 2 of the License, or
 304+ (at your option) any later version.
 305+
 306+ This program is distributed in the hope that it will be useful,
 307+ but WITHOUT ANY WARRANTY; without even the implied warranty of
 308+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 309+ GNU General Public License for more details.
 310+
 311+ You should have received a copy of the GNU General Public License
 312+ along with this program; if not, write to the Free Software
 313+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 314+
 315+
 316+Also add information on how to contact you by electronic and paper mail.
 317+
 318+If the program is interactive, make it output a short notice like this
 319+when it starts in an interactive mode:
 320+
 321+ Gnomovision version 69, Copyright (C) year name of author
 322+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 323+ This is free software, and you are welcome to redistribute it
 324+ under certain conditions; type `show c' for details.
 325+
 326+The hypothetical commands `show w' and `show c' should show the appropriate
 327+parts of the General Public License. Of course, the commands you use may
 328+be called something other than `show w' and `show c'; they could even be
 329+mouse-clicks or menu items--whatever suits your program.
 330+
 331+You should also get your employer (if you work as a programmer) or your
 332+school, if any, to sign a "copyright disclaimer" for the program, if
 333+necessary. Here is a sample; alter the names:
 334+
 335+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
 336+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
 337+
 338+ <signature of Ty Coon>, 1 April 1989
 339+
 340+ Ty Coon, President of Vice
 341+
 342+This General Public License does not permit incorporating your program into
 343+proprietary programs. If your program is a subroutine library, you may
 344+consider it more useful to permit linking proprietary applications with the
 345+library. If this is what you want to do, use the GNU Library General
 346+Public License instead of this License.
Property changes on: trunk/tools/ToolserverI18N/language/classes/LICENSE.txt
___________________________________________________________________
Added: svn:eol-style
1347 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageMk.php
@@ -0,0 +1,27 @@
 2+<?php
 3+/**
 4+ * Macedonian (Македонски)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageMk extends Language {
 9+ /**
 10+ * Plural forms per
 11+ * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#mk
 12+ *
 13+ * @param $count int
 14+ * @param $forms array
 15+ *
 16+ * @return string
 17+ */
 18+ function convertPlural( $count, $forms ) {
 19+ if ( !count( $forms ) ) { return ''; }
 20+ $forms = $this->preConvertPlural( $forms, 2 );
 21+
 22+ if ( $count % 10 === 1 && $count % 100 !== 11 ) {
 23+ return $forms[0];
 24+ } else {
 25+ return $forms[1];
 26+ }
 27+ }
 28+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageMk.php
___________________________________________________________________
Added: svn:eol-style
129 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageMl.php
@@ -0,0 +1,31 @@
 2+<?php
 3+
 4+/**
 5+ * Malayalam (മലയാളം)
 6+ *
 7+ * @ingroup Language
 8+ */
 9+class LanguageMl extends Language {
 10+ /**
 11+ * Temporary hack for the issue described at
 12+ * http://permalink.gmane.org/gmane.science.linguistics.wikipedia.technical/46396
 13+ * Convert Unicode 5.0 style Malayalam input to Unicode 5.1. Similar to
 14+ * bug 9413. Also fixes miscellaneous problems due to mishandling of ZWJ,
 15+ * e.g. bug 11162.
 16+ *
 17+ * @todo FIXME: This is language-specific for now only to avoid the negative
 18+ * performance impact of enabling it for all languages.
 19+ *
 20+ * @param $s string
 21+ *
 22+ * @return string
 23+ */
 24+ function normalize( $s ) {
 25+ global $wgFixMalayalamUnicode;
 26+ $s = parent::normalize( $s );
 27+ if ( $wgFixMalayalamUnicode ) {
 28+ $s = $this->transformUsingPairFile( 'normalize-ml.ser', $s );
 29+ }
 30+ return $s;
 31+ }
 32+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageMl.php
___________________________________________________________________
Added: svn:eol-style
133 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageEt.php
@@ -0,0 +1,23 @@
 2+<?php
 3+
 4+/** Estonian (Eesti)
 5+ *
 6+ * @ingroup Language
 7+ *
 8+ */
 9+class LanguageEt extends Language {
 10+ /**
 11+ * Avoid grouping whole numbers between 0 to 9999
 12+ *
 13+ * @param $_ string
 14+ *
 15+ * @return string
 16+ */
 17+ function commafy( $_ ) {
 18+ if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
 19+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 20+ } else {
 21+ return $_;
 22+ }
 23+ }
 24+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageEt.php
___________________________________________________________________
Added: svn:eol-style
125 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageAz.php
@@ -0,0 +1,19 @@
 2+<?php
 3+/** Azerbaijani (Azərbaycan)
 4+ *
 5+ * @ingroup Language
 6+ */
 7+class LanguageAz extends Language {
 8+
 9+ /**
 10+ * @param $string string
 11+ * @return mixed|string
 12+ */
 13+ function ucfirst ( $string ) {
 14+ if ( $string[0] == 'i' ) {
 15+ return 'İ' . substr( $string, 1 );
 16+ } else {
 17+ return parent::ucfirst( $string );
 18+ }
 19+ }
 20+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageAz.php
___________________________________________________________________
Added: svn:eol-style
121 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageMo.php
@@ -0,0 +1,30 @@
 2+<?php
 3+/**
 4+ * Moldavian (Молдовеняскэ)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageMo extends Language {
 9+
 10+ /**
 11+ * @param $count int
 12+ * @param $forms array
 13+ * @return string
 14+ */
 15+ function convertPlural( $count, $forms ) {
 16+ // Plural rules per
 17+ // http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#mo
 18+ if ( !count( $forms ) ) { return ''; }
 19+
 20+ $forms = $this->preConvertPlural( $forms, 3 );
 21+
 22+ if ( $count == 1 ) {
 23+ $index = 0;
 24+ } elseif ( $count == 0 || $count % 100 < 20 ) {
 25+ $index = 1;
 26+ } else {
 27+ $index = 2;
 28+ }
 29+ return $forms[$index];
 30+ }
 31+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageMo.php
___________________________________________________________________
Added: svn:eol-style
132 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageZh.deps.php
@@ -0,0 +1,9 @@
 2+<?php
 3+// This file exists to ensure that base classes are preloaded before
 4+// LanguageZh.php is compiled, working around a bug in the APC opcode
 5+// cache on PHP 5, where cached code can break if the include order
 6+// changed on a subsequent page view.
 7+// see http://lists.wikimedia.org/pipermail/wikitech-l/2006-January/021311.html
 8+
 9+require_once( dirname( __FILE__ ) . '/LanguageZh_hans.php' );
 10+require_once( dirname( __FILE__ ) . '/../LanguageConverter.php' );
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageZh.deps.php
___________________________________________________________________
Added: svn:eol-style
111 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageIu.php
@@ -0,0 +1,39 @@
 2+<?php
 3+/**
 4+ * @addtogroup Language
 5+ */
 6+
 7+/*
 8+* Conversion script between Latin and Syllabics for Inuktitut.
 9+* - Syllabics -> lowercase Latin
 10+* - lowercase/uppercase Latin -> Syllabics
 11+*
 12+*
 13+* Based on:
 14+* - http://commons.wikimedia.org/wiki/Image:Inuktitut.png
 15+* - LanguageSr.php
 16+*
 17+* @ingroup Language
 18+*/
 19+
 20+/**
 21+ * Inuktitut
 22+ *
 23+ * @ingroup Language
 24+ */
 25+class LanguageIu extends Language {
 26+ function __construct() {
 27+
 28+
 29+ parent::__construct();
 30+
 31+ $variants = array( 'iu', 'ike-cans', 'ike-latn' );
 32+ $variantfallbacks = array(
 33+ 'iu' => 'ike-cans',
 34+ 'ike-cans' => 'iu',
 35+ 'ike-latn' => 'iu',
 36+ );
 37+
 38+ $flags = array();
 39+ }
 40+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageIu.php
___________________________________________________________________
Added: svn:eol-style
141 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSr.deps.php
@@ -0,0 +1,9 @@
 2+<?php
 3+// This file exists to ensure that base classes are preloaded before
 4+// LanguageSr.php is compiled, working around a bug in the APC opcode
 5+// cache on PHP 5, where cached code can break if the include order
 6+// changed on a subsequent page view.
 7+// see http://lists.wikimedia.org/pipermail/wikitech-l/2006-January/021311.html
 8+
 9+require_once( dirname( __FILE__ ) . '/LanguageSr_ec.php' );
 10+require_once( dirname( __FILE__ ) . '/../LanguageConverter.php' );
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSr.deps.php
___________________________________________________________________
Added: svn:eol-style
111 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageUk.php
@@ -0,0 +1,108 @@
 2+<?php
 3+
 4+/** Ukrainian (українська мова)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageUk extends Language {
 9+
 10+ /**
 11+ * Convert from the nominative form of a noun to some other case
 12+ * Invoked with {{grammar:case|word}}
 13+ *
 14+ * @param $word string
 15+ * @param $case string
 16+ * @return string
 17+ */
 18+ function convertGrammar( $word, $case ) {
 19+ global $wgGrammarForms;
 20+ if ( isset( $wgGrammarForms['uk'][$case][$word] ) ) {
 21+ return $wgGrammarForms['uk'][$case][$word];
 22+ }
 23+
 24+ # These rules are not perfect, but they are currently only used for site names so it doesn't
 25+ # matter if they are wrong sometimes. Just add a special case for your site name if necessary.
 26+
 27+ # join and array_slice instead mb_substr
 28+ $ar = array();
 29+ preg_match_all( '/./us', $word, $ar );
 30+ if ( !preg_match( "/[a-zA-Z_]/us", $word ) )
 31+ switch ( $case ) {
 32+ case 'genitive': # родовий відмінок
 33+ if ( ( join( '', array_slice( $ar[0], -4 ) ) == 'вікі' ) || ( join( '', array_slice( $ar[0], -4 ) ) == 'Вікі' ) )
 34+ { }
 35+ elseif ( join( '', array_slice( $ar[0], -1 ) ) == 'ь' )
 36+ $word = join( '', array_slice( $ar[0], 0, -1 ) ) . 'я';
 37+ elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ія' )
 38+ $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ії';
 39+ elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ка' )
 40+ $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ки';
 41+ elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ти' )
 42+ $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'тей';
 43+ elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ди' )
 44+ $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'дів';
 45+ elseif ( join( '', array_slice( $ar[0], -3 ) ) == 'ник' )
 46+ $word = join( '', array_slice( $ar[0], 0, -3 ) ) . 'ника';
 47+ break;
 48+ case 'dative': # давальний відмінок
 49+ # stub
 50+ break;
 51+ case 'accusative': # знахідний відмінок
 52+ if ( ( join( '', array_slice( $ar[0], -4 ) ) == 'вікі' ) || ( join( '', array_slice( $ar[0], -4 ) ) == 'Вікі' ) )
 53+ { }
 54+ elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ія' )
 55+ $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ію';
 56+ break;
 57+ case 'instrumental': # орудний відмінок
 58+ # stub
 59+ break;
 60+ case 'prepositional': # місцевий відмінок
 61+ # stub
 62+ break;
 63+ }
 64+ return $word;
 65+ }
 66+
 67+ /**
 68+ * @param $count int
 69+ * @param $forms array
 70+ * @return string
 71+ */
 72+ function convertPlural( $count, $forms ) {
 73+ if ( !count( $forms ) ) { return ''; }
 74+
 75+ // if no number with word, then use $form[0] for singular and $form[1] for plural or zero
 76+ if ( count( $forms ) === 2 ) return $count == 1 ? $forms[0] : $forms[1];
 77+
 78+ // @todo FIXME: CLDR defines 4 plural forms. Form for decimals is missing/
 79+ // See http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#uk
 80+ $forms = $this->preConvertPlural( $forms, 3 );
 81+
 82+ if ( $count > 10 && floor( ( $count % 100 ) / 10 ) == 1 ) {
 83+ return $forms[2];
 84+ } else {
 85+ switch ( $count % 10 ) {
 86+ case 1: return $forms[0];
 87+ case 2:
 88+ case 3:
 89+ case 4: return $forms[1];
 90+ default: return $forms[2];
 91+ }
 92+ }
 93+ }
 94+
 95+ /**
 96+ * Ukrainian numeric format is "12 345,67" but "1234,56"
 97+ *
 98+ * @param $_ string
 99+ *
 100+ * @return string
 101+ */
 102+ function commafy( $_ ) {
 103+ if ( !preg_match( '/^\-?\d{1,4}(\.\d+)?$/', $_ ) ) {
 104+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 105+ } else {
 106+ return $_;
 107+ }
 108+ }
 109+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageUk.php
___________________________________________________________________
Added: svn:eol-style
1110 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageMt.php
@@ -0,0 +1,28 @@
 2+<?php
 3+
 4+/** Maltese (Malti)
 5+ *
 6+ * @ingroup Language
 7+ *
 8+ * @author Niklas Laxström
 9+ */
 10+
 11+class LanguageMt extends Language {
 12+
 13+ /**
 14+ * @param $count int
 15+ * @param $forms array
 16+ * @return string
 17+ */
 18+ function convertPlural( $count, $forms ) {
 19+ if ( !count( $forms ) ) { return ''; }
 20+
 21+ $forms = $this->preConvertPlural( $forms, 4 );
 22+
 23+ if ( $count === 1 ) $index = 0;
 24+ elseif ( $count === 0 || ( $count % 100 > 1 && $count % 100 < 11 ) ) $index = 1;
 25+ elseif ( $count % 100 > 10 && $count % 100 < 20 ) $index = 2;
 26+ else $index = 3;
 27+ return $forms[$index];
 28+ }
 29+}
\ No newline at end of file
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageMt.php
___________________________________________________________________
Added: svn:eol-style
130 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageTyv.php
@@ -0,0 +1,226 @@
 2+<?php
 3+
 4+/** Tyvan localization (Тыва дыл)
 5+ * From friends at tyvawiki.org
 6+ *
 7+ * @ingroup Language
 8+ */
 9+class LanguageTyv extends Language {
 10+ /**
 11+ * Grammatical transformations, needed for inflected languages
 12+ * Invoked by putting {{grammar:case|word}} in a message
 13+ *
 14+ * @param $word string
 15+ * @param $case string
 16+ * @return string
 17+ */
 18+ function convertGrammar( $word, $case ) {
 19+ global $wgGrammarForms;
 20+ if ( isset( $wgGrammarForms['tyv'][$case][$word] ) ) {
 21+ return $wgGrammarForms['tyv'][$case][$word];
 22+ }
 23+
 24+ // Set up some constants...
 25+ $allVowels = array( "е", "и", "э", "ө", "ү", "а", "ё", "о", "у", "ы", "ю", "я", "a", "e", "i", "o", "ö", "u", "ü", "y" );
 26+ $frontVowels = array( "е", "и", "э", "ө", "ү", "e", "i", "ö", "ü" );
 27+ $backVowels = array( "а", "ё", "о", "у", "ы", "ю", "я", "a", "o", "u", "y" );
 28+ $unroundFrontVowels = array( "е", "и", "э", "e", "i" );
 29+ $roundFrontVowels = array( "ө", "ү", "ö", "ü" );
 30+ $unroundBackVowels = array( "а", "ы", "я", "a", "y" );
 31+ $roundBackVowels = array( "ё", "о", "у", "ю", "o", "u" );
 32+ //$voicedPhonemes = array( "д", "б", "з", "ж", "г", "d", "b", "z", "g" );
 33+ $unvoicedPhonemes = array( "т", "п", "с", "ш", "к", "ч", "х", "t", "p", "s", "k", "x" );
 34+ $directiveUnvoicedStems = array( "т", "п", "с", "ш", "к", "ч", "х", "л", "м", "н", "ң", "t", "p", "s", "k", "x", "l", "m", "n", "ŋ" );
 35+ $directiveVoicedStems = array( "д", "б", "з", "ж", "г", "р", "й", "d", "b", "z", "g", "r", "j" );
 36+
 37+ //$allSonants = array("л", "м", "н", "ң", "р", "й");
 38+ //$allNasals = array("м", "н", "ң");
 39+
 40+ //Put the word in a form we can play with since we're using UTF-8
 41+ preg_match_all( '/./us', $word, $ar );
 42+
 43+ $wordEnding = $ar[0][count( $ar[0] ) - 1]; // Here's the last letter in the word
 44+ $wordReversed = array_reverse( $ar[0] ); // Here's an array with the order of the letters in the word reversed so we can find a match quicker *shrug*
 45+
 46+ // Find the last vowel in the word
 47+ $wordLastVowel = NULL;
 48+ foreach ( $wordReversed as $xvalue ) {
 49+ foreach ( $allVowels as $yvalue ) {
 50+ if ( strcmp( $xvalue, $yvalue ) == 0 ) {
 51+ $wordLastVowel = $xvalue;
 52+ break;
 53+ } else {
 54+ continue;
 55+ }
 56+ }
 57+ if ( $wordLastVowel !== NULL ) {
 58+ break;
 59+ } else {
 60+ continue;
 61+ }
 62+ }
 63+
 64+ // Now convert the word
 65+ switch ( $case ) {
 66+ case "genitive":
 67+ if ( in_array( $wordEnding, $unvoicedPhonemes ) ) {
 68+ if ( in_array( $wordLastVowel, $roundFrontVowels ) ) {
 69+ $word = implode( "", $ar[0] ) . "түң";
 70+ } elseif ( in_array( $wordLastVowel, $unroundFrontVowels ) ) {
 71+ $word = implode( "", $ar[0] ) . "тиң";
 72+ } elseif ( in_array( $wordLastVowel, $roundBackVowels ) ) {
 73+ $word = implode( "", $ar[0] ) . "туң";
 74+ } elseif ( in_array( $wordLastVowel, $unroundBackVowels ) ) {
 75+ $word = implode( "", $ar[0] ) . "тың";
 76+ } else {
 77+ }
 78+ } elseif ( $wordEnding === "л" || $wordEnding === "l" ) {
 79+ if ( in_array( $wordLastVowel, $roundFrontVowels ) ) {
 80+ $word = implode( "", $ar[0] ) . "дүң";
 81+ } elseif ( in_array( $wordLastVowel, $unroundFrontVowels ) ) {
 82+ $word = implode( "", $ar[0] ) . "диң";
 83+ } elseif ( in_array( $wordLastVowel, $roundBackVowels ) ) {
 84+ $word = implode( "", $ar[0] ) . "дуң";
 85+ } elseif ( in_array( $wordLastVowel, $unroundBackVowels ) ) {
 86+ $word = implode( "", $ar[0] ) . "дың";
 87+ } else {
 88+ }
 89+ } else {
 90+ if ( in_array( $wordLastVowel, $roundFrontVowels ) ) {
 91+ $word = implode( "", $ar[0] ) . "нүң";
 92+ } elseif ( in_array( $wordLastVowel, $unroundFrontVowels ) ) {
 93+ $word = implode( "", $ar[0] ) . "ниң";
 94+ } elseif ( in_array( $wordLastVowel, $roundBackVowels ) ) {
 95+ $word = implode( "", $ar[0] ) . "нуң";
 96+ } elseif ( in_array( $wordLastVowel, $unroundBackVowels ) ) {
 97+ $word = implode( "", $ar[0] ) . "ның";
 98+ } else {
 99+ }
 100+ }
 101+ break;
 102+ case "dative":
 103+ if ( in_array( $wordEnding, $unvoicedPhonemes ) ) {
 104+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 105+ $word = implode( "", $ar[0] ) . "ке";
 106+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 107+ $word = implode( "", $ar[0] ) . "ка";
 108+ } else {
 109+ }
 110+ } else {
 111+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 112+ $word = implode( "", $ar[0] ) . "ге";
 113+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 114+ $word = implode( "", $ar[0] ) . "га";
 115+ } else {
 116+ }
 117+ }
 118+ break;
 119+ case "accusative":
 120+ if ( in_array( $wordEnding, $unvoicedPhonemes ) ) {
 121+ if ( in_array( $wordLastVowel, $roundFrontVowels ) ) {
 122+ $word = implode( "", $ar[0] ) . "тү";
 123+ } elseif ( in_array( $wordLastVowel, $unroundFrontVowels ) ) {
 124+ $word = implode( "", $ar[0] ) . "ти";
 125+ } elseif ( in_array( $wordLastVowel, $roundBackVowels ) ) {
 126+ $word = implode( "", $ar[0] ) . "ту";
 127+ } elseif ( in_array( $wordLastVowel, $unroundBackVowels ) ) {
 128+ $word = implode( "", $ar[0] ) . "ты";
 129+ } else {
 130+ }
 131+ } elseif ( $wordEnding === "л" || $wordEnding === "l" ) {
 132+ if ( in_array( $wordLastVowel, $roundFrontVowels ) ) {
 133+ $word = implode( "", $ar[0] ) . "дү";
 134+ } elseif ( in_array( $wordLastVowel, $unroundFrontVowels ) ) {
 135+ $word = implode( "", $ar[0] ) . "ди";
 136+ } elseif ( in_array( $wordLastVowel, $roundBackVowels ) ) {
 137+ $word = implode( "", $ar[0] ) . "ду";
 138+ } elseif ( in_array( $wordLastVowel, $unroundBackVowels ) ) {
 139+ $word = implode( "", $ar[0] ) . "ды";
 140+ } else {
 141+ }
 142+ } else {
 143+ if ( in_array( $wordLastVowel, $roundFrontVowels ) ) {
 144+ $word = implode( "", $ar[0] ) . "нү";
 145+ } elseif ( in_array( $wordLastVowel, $unroundFrontVowels ) ) {
 146+ $word = implode( "", $ar[0] ) . "ни";
 147+ } elseif ( in_array( $wordLastVowel, $roundBackVowels ) ) {
 148+ $word = implode( "", $ar[0] ) . "ну";
 149+ } elseif ( in_array( $wordLastVowel, $unroundBackVowels ) ) {
 150+ $word = implode( "", $ar[0] ) . "ны";
 151+ } else {
 152+ }
 153+ }
 154+ break;
 155+ case "locative":
 156+ if ( in_array( $wordEnding, $unvoicedPhonemes ) ) {
 157+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 158+ $word = implode( "", $ar[0] ) . "те";
 159+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 160+ $word = implode( "", $ar[0] ) . "та";
 161+ } else {
 162+ }
 163+ } else {
 164+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 165+ $word = implode( "", $ar[0] ) . "де";
 166+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 167+ $word = implode( "", $ar[0] ) . "да";
 168+ } else {
 169+ }
 170+ }
 171+ break;
 172+ case "ablative":
 173+ if ( in_array( $wordEnding, $unvoicedPhonemes ) ) {
 174+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 175+ $word = implode( "", $ar[0] ) . "тен";
 176+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 177+ $word = implode( "", $ar[0] ) . "тан";
 178+ } else {
 179+ }
 180+ } else {
 181+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 182+ $word = implode( "", $ar[0] ) . "ден";
 183+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 184+ $word = implode( "", $ar[0] ) . "дан";
 185+ } else {
 186+ }
 187+ }
 188+ break;
 189+ case "directive1":
 190+ if ( in_array( $wordEnding, $directiveVoicedStems ) ) {
 191+ $word = implode( "", $ar[0] ) . "же";
 192+ } elseif ( in_array( $wordEnding, $directiveUnvoicedStems ) ) {
 193+ $word = implode( "", $ar[0] ) . "че";
 194+ } else {
 195+ }
 196+ break;
 197+ case "directive2":
 198+ if ( in_array( $wordEnding, $unvoicedPhonemes ) ) {
 199+ if ( in_array( $wordLastVowel, $roundFrontVowels ) ) {
 200+ $word = implode( "", $ar[0] ) . "түве";
 201+ } elseif ( in_array( $wordLastVowel, $unroundFrontVowels ) ) {
 202+ $word = implode( "", $ar[0] ) . "тиве";
 203+ } elseif ( in_array( $wordLastVowel, $roundBackVowels ) ) {
 204+ $word = implode( "", $ar[0] ) . "туве";
 205+ } elseif ( in_array( $wordLastVowel, $unroundBackVowels ) ) {
 206+ $word = implode( "", $ar[0] ) . "тыве";
 207+ } else {
 208+ }
 209+ } else {
 210+ if ( in_array( $wordLastVowel, $roundFrontVowels ) ) {
 211+ $word = implode( "", $ar[0] ) . "дүве";
 212+ } elseif ( in_array( $wordLastVowel, $unroundFrontVowels ) ) {
 213+ $word = implode( "", $ar[0] ) . "диве";
 214+ } elseif ( in_array( $wordLastVowel, $roundBackVowels ) ) {
 215+ $word = implode( "", $ar[0] ) . "дуве";
 216+ } elseif ( in_array( $wordLastVowel, $unroundBackVowels ) ) {
 217+ $word = implode( "", $ar[0] ) . "дыве";
 218+ } else {
 219+ }
 220+ }
 221+ break;
 222+ default:
 223+ break;
 224+ }
 225+ return $word;
 226+ }
 227+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageTyv.php
___________________________________________________________________
Added: svn:eol-style
1228 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageMy.php
@@ -0,0 +1,22 @@
 2+<?php
 3+
 4+/** Burmese (Myanmasa)
 5+ *
 6+ * @ingroup Language
 7+ *
 8+ * @author Niklas Laxström, 2008
 9+ */
 10+class LanguageMy extends Language {
 11+
 12+ /**
 13+ * @param $_ string
 14+ * @return string
 15+ */
 16+ function commafy( $_ ) {
 17+ /* NO-op. Cannot use
 18+ * $separatorTransformTable = array( ',' => '' )
 19+ * That would break when parsing and doing strstr '' => 'foo';
 20+ */
 21+ return $_;
 22+ }
 23+}
\ No newline at end of file
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageMy.php
___________________________________________________________________
Added: svn:eol-style
124 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageBe.php
@@ -0,0 +1,41 @@
 2+<?php
 3+/** Belarusian normative (Беларуская мова)
 4+ *
 5+ * This is still the version from Be-x-old, only duplicated for consistency of
 6+ * plural and grammar functions. If there are errors please send a patch.
 7+ *
 8+ * @ingroup Language
 9+ *
 10+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
 11+ * @link http://be.wikipedia.org/wiki/Talk:LanguageBe.php
 12+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
 13+ * @license http://www.gnu.org/copyleft/fdl.html GNU Free Documentation License
 14+ */
 15+
 16+class LanguageBe extends Language {
 17+
 18+ /**
 19+ * @param $count int
 20+ * @param $forms array
 21+ *
 22+ * @return string
 23+ */
 24+ function convertPlural( $count, $forms ) {
 25+ if ( !count( $forms ) ) { return ''; }
 26+ // @todo FIXME: CLDR defines 4 plural forms instead of 3
 27+ // http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
 28+ $forms = $this->preConvertPlural( $forms, 3 );
 29+
 30+ if ( $count > 10 && floor( ( $count % 100 ) / 10 ) == 1 ) {
 31+ return $forms[2];
 32+ } else {
 33+ switch ( $count % 10 ) {
 34+ case 1: return $forms[0];
 35+ case 2:
 36+ case 3:
 37+ case 4: return $forms[1];
 38+ default: return $forms[2];
 39+ }
 40+ }
 41+ }
 42+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageBe.php
___________________________________________________________________
Added: svn:eol-style
143 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageBg.php
@@ -0,0 +1,23 @@
 2+<?php
 3+
 4+/** Bulgarian (Български)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageBg extends Language {
 9+ /**
 10+ * ISO number formatting: 123 456 789,99.
 11+ * Avoid tripple grouping by numbers with whole part up to 4 digits.
 12+ *
 13+ * @param $_ string
 14+ *
 15+ * @return string
 16+ */
 17+ function commafy( $_ ) {
 18+ if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
 19+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 20+ } else {
 21+ return $_;
 22+ }
 23+ }
 24+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageBg.php
___________________________________________________________________
Added: svn:eol-style
125 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageBh.php
@@ -0,0 +1,22 @@
 2+<?php
 3+/**
 4+ * Bihari (भोजपुरी)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageBh extends Language {
 9+ /**
 10+ * Use singular form for zero
 11+ *
 12+ * @param $count int
 13+ * @param $forms array
 14+ *
 15+ * @return string
 16+ */
 17+ function convertPlural( $count, $forms ) {
 18+ if ( !count( $forms ) ) { return ''; }
 19+ $forms = $this->preConvertPlural( $forms, 2 );
 20+
 21+ return ( $count <= 1 ) ? $forms[0] : $forms[1];
 22+ }
 23+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageBh.php
___________________________________________________________________
Added: svn:eol-style
124 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageJa.php
@@ -0,0 +1,41 @@
 2+<?php
 3+
 4+/**
 5+ * Japanese (日本語)
 6+ *
 7+ * @ingroup Language
 8+ */
 9+class LanguageJa extends Language {
 10+
 11+ /**
 12+ * @param $string string
 13+ * @return string
 14+ */
 15+ function segmentByWord( $string ) {
 16+ // Strip known punctuation ?
 17+ // $s = preg_replace( '/\xe3\x80[\x80-\xbf]/', '', $s ); # U3000-303f
 18+
 19+ // Space strings of like hiragana/katakana/kanji
 20+ $hiragana = '(?:\xe3(?:\x81[\x80-\xbf]|\x82[\x80-\x9f]))'; # U3040-309f
 21+ $katakana = '(?:\xe3(?:\x82[\xa0-\xbf]|\x83[\x80-\xbf]))'; # U30a0-30ff
 22+ $kanji = '(?:\xe3[\x88-\xbf][\x80-\xbf]'
 23+ . '|[\xe4-\xe8][\x80-\xbf]{2}'
 24+ . '|\xe9[\x80-\xa5][\x80-\xbf]'
 25+ . '|\xe9\xa6[\x80-\x99])';
 26+ # U3200-9999 = \xe3\x88\x80-\xe9\xa6\x99
 27+ $reg = "/({$hiragana}+|{$katakana}+|{$kanji}+)/";
 28+ $s = self::insertSpace( $string, $reg );
 29+ return $s;
 30+ }
 31+
 32+ /**
 33+ * Italic is not appropriate for Japanese script
 34+ * Unfortunately most browsers do not recognise this, and render <em> as italic
 35+ *
 36+ * @param $text string
 37+ * @return string
 38+ */
 39+ function emphasize( $text ) {
 40+ return $text;
 41+ }
 42+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageJa.php
___________________________________________________________________
Added: svn:eol-style
143 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageKaa.php
@@ -0,0 +1,73 @@
 2+<?php
 3+
 4+/** Karakalpak (Qaraqalpaqsha)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageKaa extends Language {
 9+
 10+ # Convert from the nominative form of a noun to some other case
 11+ # Invoked with {{GRAMMAR:case|word}}
 12+ /**
 13+ * Cases: genitive, dative, accusative, locative, ablative, comitative + possessive forms
 14+ *
 15+ * @param $word string
 16+ * @param $case string
 17+ *
 18+ * @return string
 19+ */
 20+ function convertGrammar( $word, $case ) {
 21+ global $wgGrammarForms;
 22+ if ( isset( $wgGrammarForms['kaa'][$case][$word] ) ) {
 23+ return $wgGrammarForms['kaa'][$case][$word];
 24+ }
 25+ /* Full code of function convertGrammar() is in development. Updates coming soon. */
 26+ return $word;
 27+ }
 28+
 29+ /**
 30+ * It fixes issue with ucfirst for transforming 'i' to 'İ'
 31+ *
 32+ * @param $string string
 33+ *
 34+ * @return string
 35+ */
 36+ function ucfirst ( $string ) {
 37+ if ( substr( $string, 0, 1 ) === 'i' ) {
 38+ return 'İ' . substr( $string, 1 );
 39+ } else {
 40+ return parent::ucfirst( $string );
 41+ }
 42+ }
 43+
 44+ /**
 45+ * It fixes issue with lcfirst for transforming 'I' to 'ı'
 46+ *
 47+ * @param $string string
 48+ *
 49+ * @return string
 50+ */
 51+ function lcfirst ( $string ) {
 52+ if ( substr( $string, 0, 1 ) === 'I' ) {
 53+ return 'ı' . substr( $string, 1 );
 54+ } else {
 55+ return parent::lcfirst( $string );
 56+ }
 57+ }
 58+
 59+ /**
 60+ * Avoid grouping whole numbers between 0 to 9999
 61+ *
 62+ * @param $_ string
 63+ *
 64+ * @return string
 65+ */
 66+ function commafy( $_ ) {
 67+ if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
 68+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 69+ } else {
 70+ return $_;
 71+ }
 72+ }
 73+
 74+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageKaa.php
___________________________________________________________________
Added: svn:eol-style
175 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageFi.php
@@ -0,0 +1,146 @@
 2+<?php
 3+
 4+/** Finnish (Suomi)
 5+ *
 6+ * @ingroup Language
 7+ *
 8+ * @author Niklas Laxström
 9+ */
 10+class LanguageFi extends Language {
 11+
 12+ /**
 13+ * Convert from the nominative form of a noun to some other case
 14+ * Invoked with {{grammar:case|word}}
 15+ *
 16+ * @param $word string
 17+ * @param $case string
 18+ * @return string
 19+ */
 20+ function convertGrammar( $word, $case ) {
 21+ global $wgGrammarForms;
 22+ if ( isset( $wgGrammarForms['fi'][$case][$word] ) ) {
 23+ return $wgGrammarForms['fi'][$case][$word];
 24+ }
 25+
 26+ # These rules are not perfect, but they are currently only used for site names so it doesn't
 27+ # matter if they are wrong sometimes. Just add a special case for your site name if necessary.
 28+
 29+ # wovel harmony flag
 30+ $aou = preg_match( '/[aou][^äöy]*$/i', $word );
 31+
 32+ # The flag should be false for compounds where the last word has only neutral vowels (e/i).
 33+ # The general case cannot be handled without a dictionary, but there's at least one notable
 34+ # special case we should check for:
 35+
 36+ if ( preg_match( '/wiki$/i', $word ) )
 37+ $aou = false;
 38+
 39+ # append i after final consonant
 40+ if ( preg_match( '/[bcdfghjklmnpqrstvwxz]$/i', $word ) )
 41+ $word .= 'i';
 42+
 43+ switch ( $case ) {
 44+ case 'genitive':
 45+ $word .= 'n';
 46+ break;
 47+ case 'elative':
 48+ $word .= ( $aou ? 'sta' : 'stä' );
 49+ break;
 50+ case 'partitive':
 51+ $word .= ( $aou ? 'a' : 'ä' );
 52+ break;
 53+ case 'illative':
 54+ # Double the last letter and add 'n'
 55+ # mb_substr has a compatibility function in GlobalFunctions.php
 56+ $word = $word . mb_substr( $word, -1 ) . 'n';
 57+ break;
 58+ case 'inessive':
 59+ $word .= ( $aou ? 'ssa' : 'ssä' );
 60+ break;
 61+ }
 62+ return $word;
 63+ }
 64+
 65+ /**
 66+ * @param $str string
 67+ * @param $forContent bool
 68+ * @return string
 69+ */
 70+ function translateBlockExpiry( $str, $forContent = false ) {
 71+ /*
 72+ 'ago', 'now', 'today', 'this', 'next',
 73+ 'first', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth',
 74+ 'tomorrow', 'yesterday'
 75+
 76+ $months = 'january:tammikuu,february:helmikuu,march:maaliskuu,april:huhtikuu,may:toukokuu,june:kesäkuu,' .
 77+ 'july:heinäkuu,august:elokuu,september:syyskuu,october:lokakuu,november:marraskuu,december:joulukuu,' .
 78+ 'jan:tammikuu,feb:helmikuu,mar:maaliskuu,apr:huhtikuu,jun:kesäkuu,jul:heinäkuu,aug:elokuu,sep:syyskuu,'.
 79+ 'oct:lokakuu,nov:marraskuu,dec:joulukuu,sept:syyskuu';
 80+ */
 81+ $weekds = array(
 82+ 'monday' => 'maanantai',
 83+ 'tuesday' => 'tiistai',
 84+ 'wednesday' => 'keskiviikko',
 85+ 'thursay' => 'torstai',
 86+ 'friday' => 'perjantai',
 87+ 'saturday' => 'lauantai',
 88+ 'sunday' => 'sunnuntai',
 89+ 'mon' => 'ma',
 90+ 'tue' => 'ti',
 91+ 'tues' => 'ti',
 92+ 'wed' => 'ke',
 93+ 'wednes' => 'ke',
 94+ 'thu' => 'to',
 95+ 'thur' => 'to',
 96+ 'thurs' => 'to',
 97+ 'fri' => 'pe',
 98+ 'sat' => 'la',
 99+ 'sun' => 'su',
 100+ 'next' => 'seuraava',
 101+ 'tomorrow' => 'huomenna',
 102+ 'ago' => 'sitten',
 103+ 'seconds' => 'sekuntia',
 104+ 'second' => 'sekunti',
 105+ 'secs' => 's',
 106+ 'sec' => 's',
 107+ 'minutes' => 'minuuttia',
 108+ 'minute' => 'minuutti',
 109+ 'mins' => 'min',
 110+ 'min' => 'min',
 111+ 'days' => 'päivää',
 112+ 'day' => 'päivä',
 113+ 'hours' => 'tuntia',
 114+ 'hour' => 'tunti',
 115+ 'weeks' => 'viikkoa',
 116+ 'week' => 'viikko',
 117+ 'fortnights' => 'tuplaviikkoa',
 118+ 'fortnight' => 'tuplaviikko',
 119+ 'months' => 'kuukautta',
 120+ 'month' => 'kuukausi',
 121+ 'years' => 'vuotta',
 122+ 'year' => 'vuosi',
 123+ 'infinite' => 'ikuisesti',
 124+ 'indefinite' => 'ikuisesti'
 125+ );
 126+
 127+ $final = '';
 128+ $tokens = explode ( ' ', $str );
 129+ foreach ( $tokens as $item ) {
 130+ if ( !is_numeric( $item ) ) {
 131+ if ( count ( explode( '-', $item ) ) == 3 && strlen( $item ) == 10 ) {
 132+ list( $yyyy, $mm, $dd ) = explode( '-', $item );
 133+ $final .= ' ' . $this->date( "{$yyyy}{$mm}{$dd}000000" );
 134+ continue;
 135+ }
 136+ if ( isset( $weekds[$item] ) ) {
 137+ $final .= ' ' . $weekds[$item];
 138+ continue;
 139+ }
 140+ }
 141+
 142+ $final .= ' ' . $item;
 143+ }
 144+
 145+ return htmlspecialchars( trim( $final ) );
 146+ }
 147+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageFi.php
___________________________________________________________________
Added: svn:eol-style
1148 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageKk.deps.php
@@ -0,0 +1,9 @@
 2+<?php
 3+// This file exists to ensure that base classes are preloaded before
 4+// LanguageKk.php is compiled, working around a bug in the APC opcode
 5+// cache on PHP 5, where cached code can break if the include order
 6+// changed on a subsequent page view.
 7+// see http://lists.wikimedia.org/pipermail/wikitech-l/2006-January/021311.html
 8+
 9+require_once( dirname( __FILE__ ) . '/../LanguageConverter.php' );
 10+require_once( dirname( __FILE__ ) . '/LanguageKk_cyrl.php' );
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageKk.deps.php
___________________________________________________________________
Added: svn:eol-style
111 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageBs.php
@@ -0,0 +1,59 @@
 2+<?php
 3+
 4+/** Bosnian (bosanski)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageBs extends Language {
 9+
 10+ /**
 11+ * @param $count int
 12+ * @param $forms array
 13+ * @return string
 14+ */
 15+ function convertPlural( $count, $forms ) {
 16+ if ( !count( $forms ) ) { return ''; }
 17+ $forms = $this->preConvertPlural( $forms, 3 );
 18+
 19+ // @todo FIXME: CLDR defines 4 plural forms instead of 3. Plural for decimals is missing.
 20+ // http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
 21+ if ( $count > 10 && floor( ( $count % 100 ) / 10 ) == 1 ) {
 22+ return $forms[2];
 23+ } else {
 24+ switch ( $count % 10 ) {
 25+ case 1: return $forms[0];
 26+ case 2:
 27+ case 3:
 28+ case 4: return $forms[1];
 29+ default: return $forms[2];
 30+ }
 31+ }
 32+ }
 33+
 34+ # Convert from the nominative form of a noun to some other case
 35+ # Invoked with {{GRAMMAR:case|word}}
 36+ /**
 37+ * Cases: genitiv, dativ, akuzativ, vokativ, instrumental, lokativ
 38+ *
 39+ * @param $word string
 40+ * @param $case string
 41+ *
 42+ * @return string
 43+ */
 44+ function convertGrammar( $word, $case ) {
 45+ global $wgGrammarForms;
 46+ if ( isset( $wgGrammarForms['bs'][$case][$word] ) ) {
 47+ return $wgGrammarForms['bs'][$case][$word];
 48+ }
 49+ switch ( $case ) {
 50+ case 'instrumental': # instrumental
 51+ $word = 's ' . $word;
 52+ break;
 53+ case 'lokativ': # locative
 54+ $word = 'o ' . $word;
 55+ break;
 56+ }
 57+
 58+ return $word; # this will return the original value for 'nominativ' (nominative) and all undefined case values
 59+ }
 60+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageBs.php
___________________________________________________________________
Added: svn:eol-style
161 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageGan.php
@@ -0,0 +1,146 @@
 2+<?php
 3+
 4+require_once( dirname( __FILE__ ) . '/../LanguageConverter.php' );
 5+require_once( dirname( __FILE__ ) . '/LanguageZh.php' );
 6+
 7+/**
 8+ * @ingroup Language
 9+ */
 10+class GanConverter extends LanguageConverter {
 11+
 12+ /**
 13+ * @param $langobj Language
 14+ * @param $maincode string
 15+ * @param $variants array
 16+ * @param $variantfallbacks array
 17+ * @param $flags array
 18+ * @param $manualLevel array
 19+ */
 20+ function __construct( $langobj, $maincode,
 21+ $variants = array(),
 22+ $variantfallbacks = array(),
 23+ $flags = array(),
 24+ $manualLevel = array() ) {
 25+ $this->mDescCodeSep = ':';
 26+ $this->mDescVarSep = ';';
 27+ parent::__construct( $langobj, $maincode,
 28+ $variants,
 29+ $variantfallbacks,
 30+ $flags,
 31+ $manualLevel );
 32+ $names = array(
 33+ 'gan' => '原文',
 34+ 'gan-hans' => '简体',
 35+ 'gan-hant' => '繁體',
 36+ );
 37+ $this->mVariantNames = array_merge( $this->mVariantNames, $names );
 38+ }
 39+
 40+ function loadDefaultTables() {
 41+ require( dirname( __FILE__ ) . "/../../includes/ZhConversion.php" );
 42+ $this->mTables = array(
 43+ 'gan-hans' => new ReplacementArray( $zh2Hans ),
 44+ 'gan-hant' => new ReplacementArray( $zh2Hant ),
 45+ 'gan' => new ReplacementArray
 46+ );
 47+ }
 48+
 49+ /**
 50+ * there shouldn't be any latin text in Chinese conversion, so no need
 51+ * to mark anything.
 52+ * $noParse is there for compatibility with LanguageConvert::markNoConversion
 53+ *
 54+ * @param $text string
 55+ * @param $noParse bool
 56+ *
 57+ * @return string
 58+ */
 59+ function markNoConversion( $text, $noParse = false ) {
 60+ return $text;
 61+ }
 62+
 63+ /**
 64+ * @param $key string
 65+ * @return String
 66+ */
 67+ function convertCategoryKey( $key ) {
 68+ return $this->autoConvert( $key, 'gan' );
 69+ }
 70+}
 71+
 72+/**
 73+ * class that handles both Traditional and Simplified Chinese
 74+ * right now it only distinguish gan_hans, gan_hant.
 75+ *
 76+ * @ingroup Language
 77+ */
 78+class LanguageGan extends LanguageZh {
 79+
 80+ function __construct() {
 81+
 82+ parent::__construct();
 83+
 84+ $variants = array( 'gan', 'gan-hans', 'gan-hant' );
 85+ $variantfallbacks = array(
 86+ 'gan' => array( 'gan-hans', 'gan-hant' ),
 87+ 'gan-hans' => array( 'gan' ),
 88+ 'gan-hant' => array( 'gan' ),
 89+ );
 90+ $ml = array(
 91+ 'gan' => 'disable',
 92+ );
 93+
 94+ $this->mConverter = new GanConverter( $this, 'gan',
 95+ $variants, $variantfallbacks,
 96+ array(),
 97+ $ml );
 98+
 99+ $wgHooks['ArticleSaveComplete'][] = $this->mConverter;
 100+ }
 101+
 102+ /**
 103+ * this should give much better diff info
 104+ *
 105+ * @param $text string
 106+ * @return string
 107+ */
 108+ function segmentForDiff( $text ) {
 109+ return preg_replace(
 110+ "/([\\xc0-\\xff][\\x80-\\xbf]*)/e",
 111+ "' ' .\"$1\"", $text );
 112+ }
 113+
 114+ /**
 115+ * @param $text string
 116+ * @return string
 117+ */
 118+ function unsegmentForDiff( $text ) {
 119+ return preg_replace(
 120+ "/ ([\\xc0-\\xff][\\x80-\\xbf]*)/e",
 121+ "\"$1\"", $text );
 122+ }
 123+
 124+ /**
 125+ * word segmentation
 126+ *
 127+ * @param $string string
 128+ * @param $autoVariant string
 129+ * @return String
 130+ */
 131+ function normalizeForSearch( $string, $autoVariant = 'gan-hans' ) {
 132+ // LanguageZh::normalizeForSearch
 133+ return parent::normalizeForSearch( $string, $autoVariant );
 134+ }
 135+
 136+ /**
 137+ * @param $termsArray array
 138+ * @return array
 139+ */
 140+ function convertForSearchResult( $termsArray ) {
 141+ $terms = implode( '|', $termsArray );
 142+ $terms = self::convertDoubleWidth( $terms );
 143+ $terms = implode( '|', $this->mConverter->autoConvertToAllVariants( $terms ) );
 144+ $ret = array_unique( explode( '|', $terms ) );
 145+ return $ret;
 146+ }
 147+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageGan.php
___________________________________________________________________
Added: svn:eol-style
1148 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageFr.php
@@ -0,0 +1,22 @@
 2+<?php
 3+
 4+/** French (Français)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageFr extends Language {
 9+ /**
 10+ * Use singular form for zero (see bug 7309)
 11+ *
 12+ * @param $count int
 13+ * @param $forms array
 14+ *
 15+ * @return string
 16+ */
 17+ function convertPlural( $count, $forms ) {
 18+ if ( !count( $forms ) ) { return ''; }
 19+ $forms = $this->preConvertPlural( $forms, 2 );
 20+
 21+ return ( $count <= 1 ) ? $forms[0] : $forms[1];
 22+ }
 23+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageFr.php
___________________________________________________________________
Added: svn:eol-style
124 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageConverter.php
@@ -0,0 +1,1528 @@
 2+<?php
 3+/**
 4+ * Contains the LanguageConverter class and ConverterRule class
 5+ *
 6+ * This program is free software; you can redistribute it and/or modify
 7+ * it under the terms of the GNU General Public License as published by
 8+ * the Free Software Foundation; either version 2 of the License, or
 9+ * (at your option) any later version.
 10+ *
 11+ * This program is distributed in the hope that it will be useful,
 12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 14+ * GNU General Public License for more details.
 15+ *
 16+ * You should have received a copy of the GNU General Public License along
 17+ * with this program; if not, write to the Free Software Foundation, Inc.,
 18+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 19+ * http://www.gnu.org/copyleft/gpl.html
 20+ *
 21+ * @file
 22+ * @ingroup Language
 23+ */
 24+
 25+/**
 26+ * Base class for language conversion.
 27+ * @ingroup Language
 28+ *
 29+ * @author Zhengzhu Feng <zhengzhu@gmail.com>
 30+ * @maintainers fdcn <fdcn64@gmail.com>, shinjiman <shinjiman@gmail.com>, PhiLiP <philip.npc@gmail.com>
 31+ */
 32+class LanguageConverter {
 33+ var $mMainLanguageCode;
 34+ var $mVariants, $mVariantFallbacks, $mVariantNames;
 35+ var $mTablesLoaded = false;
 36+ var $mTables;
 37+ // 'bidirectional' 'unidirectional' 'disable' for each variant
 38+ var $mManualLevel;
 39+
 40+ /**
 41+ * @var String: memcached key name
 42+ */
 43+ var $mCacheKey;
 44+
 45+ var $mLangObj;
 46+ var $mFlags;
 47+ var $mDescCodeSep = ':', $mDescVarSep = ';';
 48+ var $mUcfirst = false;
 49+ var $mConvRuleTitle = false;
 50+ var $mURLVariant;
 51+ var $mUserVariant;
 52+ var $mHeaderVariant;
 53+ var $mMaxDepth = 10;
 54+ var $mVarSeparatorPattern;
 55+
 56+ const CACHE_VERSION_KEY = 'VERSION 6';
 57+
 58+ /**
 59+ * Constructor
 60+ *
 61+ * @param $langobj Language: the Language Object
 62+ * @param $maincode String: the main language code of this language
 63+ * @param $variants Array: the supported variants of this language
 64+ * @param $variantfallbacks Array: the fallback language of each variant
 65+ * @param $flags Array: defining the custom strings that maps to the flags
 66+ * @param $manualLevel Array: limit for supported variants
 67+ */
 68+ public function __construct( $langobj, $maincode, $variants = array(),
 69+ $variantfallbacks = array(), $flags = array(),
 70+ $manualLevel = array() ) {
 71+ global $wgDisabledVariants;
 72+ $this->mLangObj = $langobj;
 73+ $this->mMainLanguageCode = $maincode;
 74+ $this->mVariants = array_diff( $variants, $wgDisabledVariants );
 75+ $this->mVariantFallbacks = $variantfallbacks;
 76+ $this->mVariantNames = Language::getLanguageNames();
 77+ $this->mCacheKey = wfMemcKey( 'conversiontables', $maincode );
 78+ $defaultflags = array(
 79+ // 'S' show converted text
 80+ // '+' add rules for alltext
 81+ // 'E' the gave flags is error
 82+ // these flags above are reserved for program
 83+ 'A' => 'A', // add rule for convert code (all text convert)
 84+ 'T' => 'T', // title convert
 85+ 'R' => 'R', // raw content
 86+ 'D' => 'D', // convert description (subclass implement)
 87+ '-' => '-', // remove convert (not implement)
 88+ 'H' => 'H', // add rule for convert code
 89+ // (but no display in placed code)
 90+ 'N' => 'N' // current variant name
 91+ );
 92+ $this->mFlags = array_merge( $defaultflags, $flags );
 93+ foreach ( $this->mVariants as $v ) {
 94+ if ( array_key_exists( $v, $manualLevel ) ) {
 95+ $this->mManualLevel[$v] = $manualLevel[$v];
 96+ } else {
 97+ $this->mManualLevel[$v] = 'bidirectional';
 98+ }
 99+ $this->mFlags[$v] = $v;
 100+ }
 101+ }
 102+
 103+ /**
 104+ * Get all valid variants.
 105+ * Call this instead of using $this->mVariants directly.
 106+ *
 107+ * @return Array: contains all valid variants
 108+ */
 109+ public function getVariants() {
 110+ return $this->mVariants;
 111+ }
 112+
 113+ /**
 114+ * In case some variant is not defined in the markup, we need
 115+ * to have some fallback. For example, in zh, normally people
 116+ * will define zh-hans and zh-hant, but less so for zh-sg or zh-hk.
 117+ * when zh-sg is preferred but not defined, we will pick zh-hans
 118+ * in this case. Right now this is only used by zh.
 119+ *
 120+ * @param $variant String: the language code of the variant
 121+ * @return String: The code of the fallback language or the
 122+ * main code if there is no fallback
 123+ */
 124+ public function getVariantFallbacks( $variant ) {
 125+ if ( isset( $this->mVariantFallbacks[$variant] ) ) {
 126+ return $this->mVariantFallbacks[$variant];
 127+ }
 128+ return $this->mMainLanguageCode;
 129+ }
 130+
 131+ /**
 132+ * Get the title produced by the conversion rule.
 133+ * @return String: The converted title text
 134+ */
 135+ public function getConvRuleTitle() {
 136+ return $this->mConvRuleTitle;
 137+ }
 138+
 139+ /**
 140+ * Get preferred language variant.
 141+ * @return String: the preferred language code
 142+ */
 143+ public function getPreferredVariant() {
 144+ global $wgDefaultLanguageVariant, $wgUser;
 145+
 146+ $req = $this->getURLVariant();
 147+
 148+ if ( $wgUser->isLoggedIn() && !$req ) {
 149+ $req = $this->getUserVariant();
 150+ } elseif ( !$req ) {
 151+ $req = $this->getHeaderVariant();
 152+ }
 153+
 154+ if ( $wgDefaultLanguageVariant && !$req ) {
 155+ $req = $this->validateVariant( $wgDefaultLanguageVariant );
 156+ }
 157+
 158+ // This function, unlike the other get*Variant functions, is
 159+ // not memoized (i.e. there return value is not cached) since
 160+ // new information might appear during processing after this
 161+ // is first called.
 162+ if ( $req ) {
 163+ return $req;
 164+ }
 165+ return $this->mMainLanguageCode;
 166+ }
 167+
 168+ /**
 169+ * Get default variant.
 170+ * This function would not be affected by user's settings or headers
 171+ * @return String: the default variant code
 172+ */
 173+ public function getDefaultVariant() {
 174+ global $wgDefaultLanguageVariant;
 175+
 176+ $req = $this->getURLVariant();
 177+
 178+ if ( $wgDefaultLanguageVariant && !$req ) {
 179+ $req = $this->validateVariant( $wgDefaultLanguageVariant );
 180+ }
 181+
 182+ if ( $req ) {
 183+ return $req;
 184+ }
 185+ return $this->mMainLanguageCode;
 186+ }
 187+
 188+ /**
 189+ * Validate the variant
 190+ * @param $variant String: the variant to validate
 191+ * @return Mixed: returns the variant if it is valid, null otherwise
 192+ */
 193+ protected function validateVariant( $variant = null ) {
 194+ if ( $variant !== null && in_array( $variant, $this->mVariants ) ) {
 195+ return $variant;
 196+ }
 197+ return null;
 198+ }
 199+
 200+ /**
 201+ * Get the variant specified in the URL
 202+ *
 203+ * @return Mixed: variant if one found, false otherwise.
 204+ */
 205+ public function getURLVariant() {
 206+ global $wgRequest;
 207+
 208+ if ( $this->mURLVariant ) {
 209+ return $this->mURLVariant;
 210+ }
 211+
 212+ // see if the preference is set in the request
 213+ $ret = $wgRequest->getText( 'variant' );
 214+
 215+ if ( !$ret ) {
 216+ $ret = $wgRequest->getVal( 'uselang' );
 217+ }
 218+
 219+ return $this->mURLVariant = $this->validateVariant( $ret );
 220+ }
 221+
 222+ /**
 223+ * Determine if the user has a variant set.
 224+ *
 225+ * @return Mixed: variant if one found, false otherwise.
 226+ */
 227+ protected function getUserVariant() {
 228+ global $wgUser;
 229+
 230+ // memoizing this function wreaks havoc on parserTest.php
 231+ /*
 232+ if ( $this->mUserVariant ) {
 233+ return $this->mUserVariant;
 234+ }
 235+ */
 236+
 237+ // Get language variant preference from logged in users
 238+ // Don't call this on stub objects because that causes infinite
 239+ // recursion during initialisation
 240+ if ( $wgUser->isLoggedIn() ) {
 241+ $ret = $wgUser->getOption( 'variant' );
 242+ } else {
 243+ // figure out user lang without constructing wgLang to avoid
 244+ // infinite recursion
 245+ $ret = $wgUser->getOption( 'language' );
 246+ }
 247+
 248+ return $this->mUserVariant = $this->validateVariant( $ret );
 249+ }
 250+
 251+ /**
 252+ * Determine the language variant from the Accept-Language header.
 253+ *
 254+ * @return Mixed: variant if one found, false otherwise.
 255+ */
 256+ protected function getHeaderVariant() {
 257+ global $wgRequest;
 258+
 259+ if ( $this->mHeaderVariant ) {
 260+ return $this->mHeaderVariant;
 261+ }
 262+
 263+ // see if some supported language variant is set in the
 264+ // HTTP header.
 265+ $languages = array_keys( $wgRequest->getAcceptLang() );
 266+ if ( empty( $languages ) ) {
 267+ return null;
 268+ }
 269+
 270+ $fallbackLanguages = array();
 271+ foreach ( $languages as $language ) {
 272+ $this->mHeaderVariant = $this->validateVariant( $language );
 273+ if ( $this->mHeaderVariant ) {
 274+ break;
 275+ }
 276+
 277+ // To see if there are fallbacks of current language.
 278+ // We record these fallback variants, and process
 279+ // them later.
 280+ $fallbacks = $this->getVariantFallbacks( $language );
 281+ if ( is_string( $fallbacks ) ) {
 282+ $fallbackLanguages[] = $fallbacks;
 283+ } elseif ( is_array( $fallbacks ) ) {
 284+ $fallbackLanguages =
 285+ array_merge( $fallbackLanguages, $fallbacks );
 286+ }
 287+ }
 288+
 289+ if ( !$this->mHeaderVariant ) {
 290+ // process fallback languages now
 291+ $fallback_languages = array_unique( $fallbackLanguages );
 292+ foreach ( $fallback_languages as $language ) {
 293+ $this->mHeaderVariant = $this->validateVariant( $language );
 294+ if ( $this->mHeaderVariant ) {
 295+ break;
 296+ }
 297+ }
 298+ }
 299+
 300+ return $this->mHeaderVariant;
 301+ }
 302+
 303+ /**
 304+ * Dictionary-based conversion.
 305+ * This function would not parse the conversion rules.
 306+ * If you want to parse rules, try to use convert() or
 307+ * convertTo().
 308+ *
 309+ * @param $text String the text to be converted
 310+ * @param $toVariant bool|string the target language code
 311+ * @return String the converted text
 312+ */
 313+ public function autoConvert( $text, $toVariant = false ) {
 314+ wfProfileIn( __METHOD__ );
 315+
 316+ $this->loadTables();
 317+
 318+ if ( !$toVariant ) {
 319+ $toVariant = $this->getPreferredVariant();
 320+ if ( !$toVariant ) {
 321+ wfProfileOut( __METHOD__ );
 322+ return $text;
 323+ }
 324+ }
 325+
 326+ if( $this->guessVariant( $text, $toVariant ) ) {
 327+ wfProfileOut( __METHOD__ );
 328+ return $text;
 329+ }
 330+
 331+ /* we convert everything except:
 332+ 1. HTML markups (anything between < and >)
 333+ 2. HTML entities
 334+ 3. placeholders created by the parser
 335+ */
 336+ global $wgParser;
 337+ if ( isset( $wgParser ) && $wgParser->UniqPrefix() != '' ) {
 338+ $marker = '|' . $wgParser->UniqPrefix() . '[\-a-zA-Z0-9]+';
 339+ } else {
 340+ $marker = '';
 341+ }
 342+
 343+ // this one is needed when the text is inside an HTML markup
 344+ $htmlfix = '|<[^>]+$|^[^<>]*>';
 345+
 346+ // disable convert to variants between <code></code> tags
 347+ $codefix = '<code>.+?<\/code>|';
 348+ // disable convertsion of <script type="text/javascript"> ... </script>
 349+ $scriptfix = '<script.*?>.*?<\/script>|';
 350+ // disable conversion of <pre xxxx> ... </pre>
 351+ $prefix = '<pre.*?>.*?<\/pre>|';
 352+
 353+ $reg = '/' . $codefix . $scriptfix . $prefix .
 354+ '<[^>]+>|&[a-zA-Z#][a-z0-9]+;' . $marker . $htmlfix . '/s';
 355+ $startPos = 0;
 356+ $sourceBlob = '';
 357+ $literalBlob = '';
 358+
 359+ // Guard against delimiter nulls in the input
 360+ $text = str_replace( "\000", '', $text );
 361+
 362+ $markupMatches = null;
 363+ $elementMatches = null;
 364+ while ( $startPos < strlen( $text ) ) {
 365+ if ( preg_match( $reg, $text, $markupMatches, PREG_OFFSET_CAPTURE, $startPos ) ) {
 366+ $elementPos = $markupMatches[0][1];
 367+ $element = $markupMatches[0][0];
 368+ } else {
 369+ $elementPos = strlen( $text );
 370+ $element = '';
 371+ }
 372+
 373+ // Queue the part before the markup for translation in a batch
 374+ $sourceBlob .= substr( $text, $startPos, $elementPos - $startPos ) . "\000";
 375+
 376+ // Advance to the next position
 377+ $startPos = $elementPos + strlen( $element );
 378+
 379+ // Translate any alt or title attributes inside the matched element
 380+ if ( $element !== '' && preg_match( '/^(<[^>\s]*)\s([^>]*)(.*)$/', $element,
 381+ $elementMatches ) )
 382+ {
 383+ $attrs = Sanitizer::decodeTagAttributes( $elementMatches[2] );
 384+ $changed = false;
 385+ foreach ( array( 'title', 'alt' ) as $attrName ) {
 386+ if ( !isset( $attrs[$attrName] ) ) {
 387+ continue;
 388+ }
 389+ $attr = $attrs[$attrName];
 390+ // Don't convert URLs
 391+ if ( !strpos( $attr, '://' ) ) {
 392+ $attr = $this->translate( $attr, $toVariant );
 393+ }
 394+
 395+ // Remove HTML tags to avoid disrupting the layout
 396+ $attr = preg_replace( '/<[^>]+>/', '', $attr );
 397+ if ( $attr !== $attrs[$attrName] ) {
 398+ $attrs[$attrName] = $attr;
 399+ $changed = true;
 400+ }
 401+ }
 402+ if ( $changed ) {
 403+ $element = $elementMatches[1] . Html::expandAttributes( $attrs ) .
 404+ $elementMatches[3];
 405+ }
 406+ }
 407+ $literalBlob .= $element . "\000";
 408+ }
 409+
 410+ // Do the main translation batch
 411+ $translatedBlob = $this->translate( $sourceBlob, $toVariant );
 412+
 413+ // Put the output back together
 414+ $translatedIter = StringUtils::explode( "\000", $translatedBlob );
 415+ $literalIter = StringUtils::explode( "\000", $literalBlob );
 416+ $output = '';
 417+ while ( $translatedIter->valid() && $literalIter->valid() ) {
 418+ $output .= $translatedIter->current();
 419+ $output .= $literalIter->current();
 420+ $translatedIter->next();
 421+ $literalIter->next();
 422+ }
 423+
 424+ wfProfileOut( __METHOD__ );
 425+ return $output;
 426+ }
 427+
 428+ /**
 429+ * Translate a string to a variant.
 430+ * Doesn't parse rules or do any of that other stuff, for that use
 431+ * convert() or convertTo().
 432+ *
 433+ * @param $text String: text to convert
 434+ * @param $variant String: variant language code
 435+ * @return String: translated text
 436+ */
 437+ public function translate( $text, $variant ) {
 438+ wfProfileIn( __METHOD__ );
 439+ // If $text is empty or only includes spaces, do nothing
 440+ // Otherwise translate it
 441+ if ( trim( $text ) ) {
 442+ $this->loadTables();
 443+ $text = $this->mTables[$variant]->replace( $text );
 444+ }
 445+ wfProfileOut( __METHOD__ );
 446+ return $text;
 447+ }
 448+
 449+ /**
 450+ * Call translate() to convert text to all valid variants.
 451+ *
 452+ * @param $text String: the text to be converted
 453+ * @return Array: variant => converted text
 454+ */
 455+ public function autoConvertToAllVariants( $text ) {
 456+ wfProfileIn( __METHOD__ );
 457+ $this->loadTables();
 458+
 459+ $ret = array();
 460+ foreach ( $this->mVariants as $variant ) {
 461+ $ret[$variant] = $this->translate( $text, $variant );
 462+ }
 463+
 464+ wfProfileOut( __METHOD__ );
 465+ return $ret;
 466+ }
 467+
 468+ /**
 469+ * Convert link text to all valid variants.
 470+ * In the first, this function only convert text outside the
 471+ * "-{" "}-" markups. Since the "{" and "}" are not allowed in
 472+ * titles, the text will get all converted always.
 473+ * So I removed this feature and deprecated the function.
 474+ *
 475+ * @param $text String: the text to be converted
 476+ * @return Array: variant => converted text
 477+ * @deprecated since 1.17 Use autoConvertToAllVariants() instead
 478+ */
 479+ public function convertLinkToAllVariants( $text ) {
 480+ return $this->autoConvertToAllVariants( $text );
 481+ }
 482+
 483+ /**
 484+ * Apply manual conversion rules.
 485+ *
 486+ * @param $convRule ConverterRule Object of ConverterRule
 487+ */
 488+ protected function applyManualConv( $convRule ) {
 489+ // Use syntax -{T|zh-cn:TitleCN; zh-tw:TitleTw}- to custom
 490+ // title conversion.
 491+ // Bug 24072: $mConvRuleTitle was overwritten by other manual
 492+ // rule(s) not for title, this breaks the title conversion.
 493+ $newConvRuleTitle = $convRule->getTitle();
 494+ if ( $newConvRuleTitle ) {
 495+ // So I add an empty check for getTitle()
 496+ $this->mConvRuleTitle = $newConvRuleTitle;
 497+ }
 498+
 499+ // merge/remove manual conversion rules to/from global table
 500+ $convTable = $convRule->getConvTable();
 501+ $action = $convRule->getRulesAction();
 502+ foreach ( $convTable as $variant => $pair ) {
 503+ if ( !$this->validateVariant( $variant ) ) {
 504+ continue;
 505+ }
 506+
 507+ if ( $action == 'add' ) {
 508+ foreach ( $pair as $from => $to ) {
 509+ // to ensure that $from and $to not be left blank
 510+ // so $this->translate() could always return a string
 511+ if ( $from || $to ) {
 512+ // more efficient than array_merge(), about 2.5 times.
 513+ $this->mTables[$variant]->setPair( $from, $to );
 514+ }
 515+ }
 516+ } elseif ( $action == 'remove' ) {
 517+ $this->mTables[$variant]->removeArray( $pair );
 518+ }
 519+ }
 520+ }
 521+
 522+ /**
 523+ * Auto convert a Title object to a readable string in the
 524+ * preferred variant.
 525+ *
 526+ * @param $title Title a object of Title
 527+ * @return String: converted title text
 528+ */
 529+ public function convertTitle( $title ) {
 530+ $variant = $this->getPreferredVariant();
 531+ $index = $title->getNamespace();
 532+ if ( $index === NS_MAIN ) {
 533+ $text = '';
 534+ } else {
 535+ // first let's check if a message has given us a converted name
 536+ $nsConvMsg = wfMessage( 'conversion-ns' . $index )->inContentLanguage();
 537+ if ( $nsConvMsg->exists() ) {
 538+ $text = $nsConvMsg->plain();
 539+ } else {
 540+ // the message does not exist, try retrieve it from the current
 541+ // variant's namespace names.
 542+ $langObj = $this->mLangObj->factory( $variant );
 543+ $text = $langObj->getFormattedNsText( $index );
 544+ }
 545+ $text .= ':';
 546+ }
 547+ $text .= $title->getText();
 548+ $text = $this->translate( $text, $variant );
 549+ return $text;
 550+ }
 551+
 552+ /**
 553+ * Convert text to different variants of a language. The automatic
 554+ * conversion is done in autoConvert(). Here we parse the text
 555+ * marked with -{}-, which specifies special conversions of the
 556+ * text that can not be accomplished in autoConvert().
 557+ *
 558+ * Syntax of the markup:
 559+ * -{code1:text1;code2:text2;...}- or
 560+ * -{flags|code1:text1;code2:text2;...}- or
 561+ * -{text}- in which case no conversion should take place for text
 562+ *
 563+ * @param $text String: text to be converted
 564+ * @return String: converted text
 565+ */
 566+ public function convert( $text ) {
 567+ $variant = $this->getPreferredVariant();
 568+ return $this->convertTo( $text, $variant );
 569+ }
 570+
 571+ /**
 572+ * Same as convert() except a extra parameter to custom variant.
 573+ *
 574+ * @param $text String: text to be converted
 575+ * @param $variant String: the target variant code
 576+ * @return String: converted text
 577+ */
 578+ public function convertTo( $text, $variant ) {
 579+ global $wgDisableLangConversion;
 580+ if ( $wgDisableLangConversion || $this->guessVariant( $text, $variant ) ) {
 581+ return $text;
 582+ }
 583+ return $this->recursiveConvertTopLevel( $text, $variant );
 584+ }
 585+
 586+ /**
 587+ * Recursively convert text on the outside. Allow to use nested
 588+ * markups to custom rules.
 589+ *
 590+ * @param $text String: text to be converted
 591+ * @param $variant String: the target variant code
 592+ * @param $depth Integer: depth of recursion
 593+ * @return String: converted text
 594+ */
 595+ protected function recursiveConvertTopLevel( $text, $variant, $depth = 0 ) {
 596+ $startPos = 0;
 597+ $out = '';
 598+ $length = strlen( $text );
 599+ while ( $startPos < $length ) {
 600+ $pos = strpos( $text, '-{', $startPos );
 601+
 602+ if ( $pos === false ) {
 603+ // No more markup, append final segment
 604+ $out .= $this->autoConvert( substr( $text, $startPos ), $variant );
 605+ return $out;
 606+ }
 607+
 608+ // Markup found
 609+ // Append initial segment
 610+ $out .= $this->autoConvert( substr( $text, $startPos, $pos - $startPos ), $variant );
 611+
 612+ // Advance position
 613+ $startPos = $pos;
 614+
 615+ // Do recursive conversion
 616+ $out .= $this->recursiveConvertRule( $text, $variant, $startPos, $depth + 1 );
 617+ }
 618+
 619+ return $out;
 620+ }
 621+
 622+ /**
 623+ * Recursively convert text on the inside.
 624+ *
 625+ * @param $text String: text to be converted
 626+ * @param $variant String: the target variant code
 627+ * @param $startPos int
 628+ * @param $depth Integer: depth of recursion
 629+ *
 630+ * @return String: converted text
 631+ */
 632+ protected function recursiveConvertRule( $text, $variant, &$startPos, $depth = 0 ) {
 633+ // Quick sanity check (no function calls)
 634+ if ( $text[$startPos] !== '-' || $text[$startPos + 1] !== '{' ) {
 635+ throw new MWException( __METHOD__ . ': invalid input string' );
 636+ }
 637+
 638+ $startPos += 2;
 639+ $inner = '';
 640+ $warningDone = false;
 641+ $length = strlen( $text );
 642+
 643+ while ( $startPos < $length ) {
 644+ $m = false;
 645+ preg_match( '/-\{|\}-/', $text, $m, PREG_OFFSET_CAPTURE, $startPos );
 646+ if ( !$m ) {
 647+ // Unclosed rule
 648+ break;
 649+ }
 650+
 651+ $token = $m[0][0];
 652+ $pos = $m[0][1];
 653+
 654+ // Markup found
 655+ // Append initial segment
 656+ $inner .= substr( $text, $startPos, $pos - $startPos );
 657+
 658+ // Advance position
 659+ $startPos = $pos;
 660+
 661+ switch ( $token ) {
 662+ case '-{':
 663+ // Check max depth
 664+ if ( $depth >= $this->mMaxDepth ) {
 665+ $inner .= '-{';
 666+ if ( !$warningDone ) {
 667+ $inner .= '<span class="error">' .
 668+ wfMsgForContent( 'language-converter-depth-warning',
 669+ $this->mMaxDepth ) .
 670+ '</span>';
 671+ $warningDone = true;
 672+ }
 673+ $startPos += 2;
 674+ continue;
 675+ }
 676+ // Recursively parse another rule
 677+ $inner .= $this->recursiveConvertRule( $text, $variant, $startPos, $depth + 1 );
 678+ break;
 679+ case '}-':
 680+ // Apply the rule
 681+ $startPos += 2;
 682+ $rule = new ConverterRule( $inner, $this );
 683+ $rule->parse( $variant );
 684+ $this->applyManualConv( $rule );
 685+ return $rule->getDisplay();
 686+ default:
 687+ throw new MWException( __METHOD__ . ': invalid regex match' );
 688+ }
 689+ }
 690+
 691+ // Unclosed rule
 692+ if ( $startPos < $length ) {
 693+ $inner .= substr( $text, $startPos );
 694+ }
 695+ $startPos = $length;
 696+ return '-{' . $this->autoConvert( $inner, $variant );
 697+ }
 698+
 699+ /**
 700+ * If a language supports multiple variants, it is possible that
 701+ * non-existing link in one variant actually exists in another variant.
 702+ * This function tries to find it. See e.g. LanguageZh.php
 703+ *
 704+ * @param $link String: the name of the link
 705+ * @param $nt Mixed: the title object of the link
 706+ * @param $ignoreOtherCond Boolean: to disable other conditions when
 707+ * we need to transclude a template or update a category's link
 708+ * @return Null, the input parameters may be modified upon return
 709+ */
 710+ public function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ) {
 711+ # If the article has already existed, there is no need to
 712+ # check it again, otherwise it may cause a fault.
 713+ if ( is_object( $nt ) && $nt->exists() ) {
 714+ return;
 715+ }
 716+
 717+ global $wgDisableLangConversion, $wgDisableTitleConversion, $wgRequest,
 718+ $wgUser;
 719+ $isredir = $wgRequest->getText( 'redirect', 'yes' );
 720+ $action = $wgRequest->getText( 'action' );
 721+ $linkconvert = $wgRequest->getText( 'linkconvert', 'yes' );
 722+ $disableLinkConversion = $wgDisableLangConversion
 723+ || $wgDisableTitleConversion;
 724+ $linkBatch = new LinkBatch();
 725+
 726+ $ns = NS_MAIN;
 727+
 728+ if ( $disableLinkConversion ||
 729+ ( !$ignoreOtherCond &&
 730+ ( $isredir == 'no'
 731+ || $action == 'edit'
 732+ || $action == 'submit'
 733+ || $linkconvert == 'no'
 734+ || $wgUser->getOption( 'noconvertlink' ) == 1 ) ) ) {
 735+ return;
 736+ }
 737+
 738+ if ( is_object( $nt ) ) {
 739+ $ns = $nt->getNamespace();
 740+ }
 741+
 742+ $variants = $this->autoConvertToAllVariants( $link );
 743+ if ( !$variants ) { // give up
 744+ return;
 745+ }
 746+
 747+ $titles = array();
 748+
 749+ foreach ( $variants as $v ) {
 750+ if ( $v != $link ) {
 751+ $varnt = Title::newFromText( $v, $ns );
 752+ if ( !is_null( $varnt ) ) {
 753+ $linkBatch->addObj( $varnt );
 754+ $titles[] = $varnt;
 755+ }
 756+ }
 757+ }
 758+
 759+ // fetch all variants in single query
 760+ $linkBatch->execute();
 761+
 762+ foreach ( $titles as $varnt ) {
 763+ if ( $varnt->getArticleID() > 0 ) {
 764+ $nt = $varnt;
 765+ $link = $varnt->getText();
 766+ break;
 767+ }
 768+ }
 769+ }
 770+
 771+ /**
 772+ * Returns language specific hash options.
 773+ *
 774+ * @return string
 775+ */
 776+ public function getExtraHashOptions() {
 777+ $variant = $this->getPreferredVariant();
 778+ return '!' . $variant;
 779+ }
 780+
 781+ /**
 782+ * Guess if a text is written in a variant. This should be implemented in subclasses.
 783+ *
 784+ * @param string $text the text to be checked
 785+ * @param string $variant language code of the variant to be checked for
 786+ * @return bool true if $text appears to be written in $variant, false if not
 787+ *
 788+ * @author Nikola Smolenski <smolensk@eunet.rs>
 789+ * @since 1.18
 790+ */
 791+ public function guessVariant($text, $variant) {
 792+ return false;
 793+ }
 794+
 795+ /**
 796+ * Load default conversion tables.
 797+ * This method must be implemented in derived class.
 798+ *
 799+ * @private
 800+ */
 801+ function loadDefaultTables() {
 802+ $name = get_class( $this );
 803+ throw new MWException( "Must implement loadDefaultTables() method in class $name" );
 804+ }
 805+
 806+ /**
 807+ * Load conversion tables either from the cache or the disk.
 808+ * @private
 809+ * @param $fromCache Boolean: load from memcached? Defaults to true.
 810+ */
 811+ function loadTables( $fromCache = true ) {
 812+ if ( $this->mTablesLoaded ) {
 813+ return;
 814+ }
 815+ global $wgMemc;
 816+ wfProfileIn( __METHOD__ );
 817+ $this->mTablesLoaded = true;
 818+ $this->mTables = false;
 819+ if ( $fromCache ) {
 820+ wfProfileIn( __METHOD__ . '-cache' );
 821+ $this->mTables = $wgMemc->get( $this->mCacheKey );
 822+ wfProfileOut( __METHOD__ . '-cache' );
 823+ }
 824+ if ( !$this->mTables
 825+ || !array_key_exists( self::CACHE_VERSION_KEY, $this->mTables ) ) {
 826+ wfProfileIn( __METHOD__ . '-recache' );
 827+ // not in cache, or we need a fresh reload.
 828+ // We will first load the default tables
 829+ // then update them using things in MediaWiki:Conversiontable/*
 830+ $this->loadDefaultTables();
 831+ foreach ( $this->mVariants as $var ) {
 832+ $cached = $this->parseCachedTable( $var );
 833+ $this->mTables[$var]->mergeArray( $cached );
 834+ }
 835+
 836+ $this->postLoadTables();
 837+ $this->mTables[self::CACHE_VERSION_KEY] = true;
 838+
 839+ $wgMemc->set( $this->mCacheKey, $this->mTables, 43200 );
 840+ wfProfileOut( __METHOD__ . '-recache' );
 841+ }
 842+ wfProfileOut( __METHOD__ );
 843+ }
 844+
 845+ /**
 846+ * Hook for post processing after conversion tables are loaded.
 847+ */
 848+ function postLoadTables() { }
 849+
 850+ /**
 851+ * Reload the conversion tables.
 852+ *
 853+ * @private
 854+ */
 855+ function reloadTables() {
 856+ if ( $this->mTables ) {
 857+ unset( $this->mTables );
 858+ }
 859+ $this->mTablesLoaded = false;
 860+ $this->loadTables( false );
 861+ }
 862+
 863+ /**
 864+ * Parse the conversion table stored in the cache.
 865+ *
 866+ * The tables should be in blocks of the following form:
 867+ * -{
 868+ * word => word ;
 869+ * word => word ;
 870+ * ...
 871+ * }-
 872+ *
 873+ * To make the tables more manageable, subpages are allowed
 874+ * and will be parsed recursively if $recursive == true.
 875+ *
 876+ * @param $code String: language code
 877+ * @param $subpage String: subpage name
 878+ * @param $recursive Boolean: parse subpages recursively? Defaults to true.
 879+ *
 880+ * @return array
 881+ */
 882+ function parseCachedTable( $code, $subpage = '', $recursive = true ) {
 883+ static $parsed = array();
 884+
 885+ $key = 'Conversiontable/' . $code;
 886+ if ( $subpage ) {
 887+ $key .= '/' . $subpage;
 888+ }
 889+ if ( array_key_exists( $key, $parsed ) ) {
 890+ return array();
 891+ }
 892+
 893+ if ( strpos( $code, '/' ) === false ) {
 894+ $txt = MessageCache::singleton()->get( 'Conversiontable', true, $code );
 895+ if ( $txt === false ) {
 896+ # @todo FIXME: This method doesn't seem to be expecting
 897+ # this possible outcome...
 898+ $txt = '&lt;Conversiontable&gt;';
 899+ }
 900+ } else {
 901+ $title = Title::makeTitleSafe(
 902+ NS_MEDIAWIKI,
 903+ "Conversiontable/$code"
 904+ );
 905+ if ( $title && $title->exists() ) {
 906+ $article = new Article( $title );
 907+ $txt = $article->getContents();
 908+ } else {
 909+ $txt = '';
 910+ }
 911+ }
 912+
 913+ // get all subpage links of the form
 914+ // [[MediaWiki:Conversiontable/zh-xx/...|...]]
 915+ $linkhead = $this->mLangObj->getNsText( NS_MEDIAWIKI ) .
 916+ ':Conversiontable';
 917+ $subs = StringUtils::explode( '[[', $txt );
 918+ $sublinks = array();
 919+ foreach ( $subs as $sub ) {
 920+ $link = explode( ']]', $sub, 2 );
 921+ if ( count( $link ) != 2 ) {
 922+ continue;
 923+ }
 924+ $b = explode( '|', $link[0], 2 );
 925+ $b = explode( '/', trim( $b[0] ), 3 );
 926+ if ( count( $b ) == 3 ) {
 927+ $sublink = $b[2];
 928+ } else {
 929+ $sublink = '';
 930+ }
 931+
 932+ if ( $b[0] == $linkhead && $b[1] == $code ) {
 933+ $sublinks[] = $sublink;
 934+ }
 935+ }
 936+
 937+ // parse the mappings in this page
 938+ $blocks = StringUtils::explode( '-{', $txt );
 939+ $ret = array();
 940+ $first = true;
 941+ foreach ( $blocks as $block ) {
 942+ if ( $first ) {
 943+ // Skip the part before the first -{
 944+ $first = false;
 945+ continue;
 946+ }
 947+ $mappings = explode( '}-', $block, 2 );
 948+ $stripped = str_replace( array( "'", '"', '*', '#' ), '',
 949+ $mappings[0] );
 950+ $table = StringUtils::explode( ';', $stripped );
 951+ foreach ( $table as $t ) {
 952+ $m = explode( '=>', $t, 3 );
 953+ if ( count( $m ) != 2 ) {
 954+ continue;
 955+ }
 956+ // trim any trailling comments starting with '//'
 957+ $tt = explode( '//', $m[1], 2 );
 958+ $ret[trim( $m[0] )] = trim( $tt[0] );
 959+ }
 960+ }
 961+ $parsed[$key] = true;
 962+
 963+ // recursively parse the subpages
 964+ if ( $recursive ) {
 965+ foreach ( $sublinks as $link ) {
 966+ $s = $this->parseCachedTable( $code, $link, $recursive );
 967+ $ret = array_merge( $ret, $s );
 968+ }
 969+ }
 970+
 971+ if ( $this->mUcfirst ) {
 972+ foreach ( $ret as $k => $v ) {
 973+ $ret[$this->mLangObj->ucfirst( $k )] = $this->mLangObj->ucfirst( $v );
 974+ }
 975+ }
 976+ return $ret;
 977+ }
 978+
 979+ /**
 980+ * Enclose a string with the "no conversion" tag. This is used by
 981+ * various functions in the Parser.
 982+ *
 983+ * @param $text String: text to be tagged for no conversion
 984+ * @param $noParse Boolean: unused
 985+ * @return String: the tagged text
 986+ */
 987+ public function markNoConversion( $text, $noParse = false ) {
 988+ # don't mark if already marked
 989+ if ( strpos( $text, '-{' ) || strpos( $text, '}-' ) ) {
 990+ return $text;
 991+ }
 992+
 993+ $ret = "-{R|$text}-";
 994+ return $ret;
 995+ }
 996+
 997+ /**
 998+ * Convert the sorting key for category links. This should make different
 999+ * keys that are variants of each other map to the same key.
 1000+ *
 1001+ * @param $key string
 1002+ *
 1003+ * @return string
 1004+ */
 1005+ function convertCategoryKey( $key ) {
 1006+ return $key;
 1007+ }
 1008+
 1009+ /**
 1010+ * Hook to refresh the cache of conversion tables when
 1011+ * MediaWiki:Conversiontable* is updated.
 1012+ * @private
 1013+ *
 1014+ * @param $article Article object
 1015+ * @param $user Object: User object for the current user
 1016+ * @param $text String: article text (?)
 1017+ * @param $summary String: edit summary of the edit
 1018+ * @param $isMinor Boolean: was the edit marked as minor?
 1019+ * @param $isWatch Boolean: did the user watch this page or not?
 1020+ * @param $section Unused
 1021+ * @param $flags Bitfield
 1022+ * @param $revision Object: new Revision object or null
 1023+ * @return Boolean: true
 1024+ */
 1025+ function OnArticleSaveComplete( $article, $user, $text, $summary, $isMinor,
 1026+ $isWatch, $section, $flags, $revision ) {
 1027+ $titleobj = $article->getTitle();
 1028+ if ( $titleobj->getNamespace() == NS_MEDIAWIKI ) {
 1029+ $title = $titleobj->getDBkey();
 1030+ $t = explode( '/', $title, 3 );
 1031+ $c = count( $t );
 1032+ if ( $c > 1 && $t[0] == 'Conversiontable' ) {
 1033+ if ( $this->validateVariant( $t[1] ) ) {
 1034+ $this->reloadTables();
 1035+ }
 1036+ }
 1037+ }
 1038+ return true;
 1039+ }
 1040+
 1041+ /**
 1042+ * Armour rendered math against conversion.
 1043+ * Escape special chars in parsed math text. (in most cases are img elements)
 1044+ *
 1045+ * @param $text String: text to armour against conversion
 1046+ * @return String: armoured text where { and } have been converted to
 1047+ * &#123; and &#125;
 1048+ */
 1049+ public function armourMath( $text ) {
 1050+ // convert '-{' and '}-' to '-&#123;' and '&#125;-' to prevent
 1051+ // any unwanted markup appearing in the math image tag.
 1052+ $text = strtr( $text, array( '-{' => '-&#123;', '}-' => '&#125;-' ) );
 1053+ return $text;
 1054+ }
 1055+
 1056+ /**
 1057+ * Get the cached separator pattern for ConverterRule::parseRules()
 1058+ */
 1059+ function getVarSeparatorPattern() {
 1060+ if ( is_null( $this->mVarSeparatorPattern ) ) {
 1061+ // varsep_pattern for preg_split:
 1062+ // text should be splited by ";" only if a valid variant
 1063+ // name exist after the markup, for example:
 1064+ // -{zh-hans:<span style="font-size:120%;">xxx</span>;zh-hant:\
 1065+ // <span style="font-size:120%;">yyy</span>;}-
 1066+ // we should split it as:
 1067+ // array(
 1068+ // [0] => 'zh-hans:<span style="font-size:120%;">xxx</span>'
 1069+ // [1] => 'zh-hant:<span style="font-size:120%;">yyy</span>'
 1070+ // [2] => ''
 1071+ // )
 1072+ $pat = '/;\s*(?=';
 1073+ foreach ( $this->mVariants as $variant ) {
 1074+ // zh-hans:xxx;zh-hant:yyy
 1075+ $pat .= $variant . '\s*:|';
 1076+ // xxx=>zh-hans:yyy; xxx=>zh-hant:zzz
 1077+ $pat .= '[^;]*?=>\s*' . $variant . '\s*:|';
 1078+ }
 1079+ $pat .= '\s*$)/';
 1080+ $this->mVarSeparatorPattern = $pat;
 1081+ }
 1082+ return $this->mVarSeparatorPattern;
 1083+ }
 1084+}
 1085+
 1086+/**
 1087+ * Parser for rules of language conversion , parse rules in -{ }- tag.
 1088+ * @ingroup Language
 1089+ * @author fdcn <fdcn64@gmail.com>, PhiLiP <philip.npc@gmail.com>
 1090+ */
 1091+class ConverterRule {
 1092+ var $mText; // original text in -{text}-
 1093+ var $mConverter; // LanguageConverter object
 1094+ var $mManualCodeError = '<strong class="error">code error!</strong>';
 1095+ var $mRuleDisplay = '';
 1096+ var $mRuleTitle = false;
 1097+ var $mRules = '';// string : the text of the rules
 1098+ var $mRulesAction = 'none';
 1099+ var $mFlags = array();
 1100+ var $mVariantFlags = array();
 1101+ var $mConvTable = array();
 1102+ var $mBidtable = array();// array of the translation in each variant
 1103+ var $mUnidtable = array();// array of the translation in each variant
 1104+
 1105+ /**
 1106+ * Constructor
 1107+ *
 1108+ * @param $text String: the text between -{ and }-
 1109+ * @param $converter LanguageConverter object
 1110+ */
 1111+ public function __construct( $text, $converter ) {
 1112+ $this->mText = $text;
 1113+ $this->mConverter = $converter;
 1114+ }
 1115+
 1116+ /**
 1117+ * Check if variants array in convert array.
 1118+ *
 1119+ * @param $variants Array or string: variant language code
 1120+ * @return String: translated text
 1121+ */
 1122+ public function getTextInBidtable( $variants ) {
 1123+ $variants = (array)$variants;
 1124+ if ( !$variants ) {
 1125+ return false;
 1126+ }
 1127+ foreach ( $variants as $variant ) {
 1128+ if ( isset( $this->mBidtable[$variant] ) ) {
 1129+ return $this->mBidtable[$variant];
 1130+ }
 1131+ }
 1132+ return false;
 1133+ }
 1134+
 1135+ /**
 1136+ * Parse flags with syntax -{FLAG| ... }-
 1137+ * @private
 1138+ */
 1139+ function parseFlags() {
 1140+ $text = $this->mText;
 1141+ $flags = array();
 1142+ $variantFlags = array();
 1143+
 1144+ $sepPos = strpos( $text, '|' );
 1145+ if ( $sepPos !== false ) {
 1146+ $validFlags = $this->mConverter->mFlags;
 1147+ $f = StringUtils::explode( ';', substr( $text, 0, $sepPos ) );
 1148+ foreach ( $f as $ff ) {
 1149+ $ff = trim( $ff );
 1150+ if ( isset( $validFlags[$ff] ) ) {
 1151+ $flags[$validFlags[$ff]] = true;
 1152+ }
 1153+ }
 1154+ $text = strval( substr( $text, $sepPos + 1 ) );
 1155+ }
 1156+
 1157+ if ( !$flags ) {
 1158+ $flags['S'] = true;
 1159+ } elseif ( isset( $flags['R'] ) ) {
 1160+ $flags = array( 'R' => true );// remove other flags
 1161+ } elseif ( isset( $flags['N'] ) ) {
 1162+ $flags = array( 'N' => true );// remove other flags
 1163+ } elseif ( isset( $flags['-'] ) ) {
 1164+ $flags = array( '-' => true );// remove other flags
 1165+ } elseif ( count( $flags ) == 1 && isset( $flags['T'] ) ) {
 1166+ $flags['H'] = true;
 1167+ } elseif ( isset( $flags['H'] ) ) {
 1168+ // replace A flag, and remove other flags except T
 1169+ $temp = array( '+' => true, 'H' => true );
 1170+ if ( isset( $flags['T'] ) ) {
 1171+ $temp['T'] = true;
 1172+ }
 1173+ if ( isset( $flags['D'] ) ) {
 1174+ $temp['D'] = true;
 1175+ }
 1176+ $flags = $temp;
 1177+ } else {
 1178+ if ( isset( $flags['A'] ) ) {
 1179+ $flags['+'] = true;
 1180+ $flags['S'] = true;
 1181+ }
 1182+ if ( isset( $flags['D'] ) ) {
 1183+ unset( $flags['S'] );
 1184+ }
 1185+ // try to find flags like "zh-hans", "zh-hant"
 1186+ // allow syntaxes like "-{zh-hans;zh-hant|XXXX}-"
 1187+ $variantFlags = array_intersect( array_keys( $flags ), $this->mConverter->mVariants );
 1188+ if ( $variantFlags ) {
 1189+ $variantFlags = array_flip( $variantFlags );
 1190+ $flags = array();
 1191+ }
 1192+ }
 1193+ $this->mVariantFlags = $variantFlags;
 1194+ $this->mRules = $text;
 1195+ $this->mFlags = $flags;
 1196+ }
 1197+
 1198+ /**
 1199+ * Generate conversion table.
 1200+ * @private
 1201+ */
 1202+ function parseRules() {
 1203+ $rules = $this->mRules;
 1204+ $bidtable = array();
 1205+ $unidtable = array();
 1206+ $variants = $this->mConverter->mVariants;
 1207+ $varsep_pattern = $this->mConverter->getVarSeparatorPattern();
 1208+
 1209+ $choice = preg_split( $varsep_pattern, $rules );
 1210+
 1211+ foreach ( $choice as $c ) {
 1212+ $v = explode( ':', $c, 2 );
 1213+ if ( count( $v ) != 2 ) {
 1214+ // syntax error, skip
 1215+ continue;
 1216+ }
 1217+ $to = trim( $v[1] );
 1218+ $v = trim( $v[0] );
 1219+ $u = explode( '=>', $v, 2 );
 1220+ // if $to is empty, strtr() could return a wrong result
 1221+ if ( count( $u ) == 1 && $to && in_array( $v, $variants ) ) {
 1222+ $bidtable[$v] = $to;
 1223+ } elseif ( count( $u ) == 2 ) {
 1224+ $from = trim( $u[0] );
 1225+ $v = trim( $u[1] );
 1226+ if ( array_key_exists( $v, $unidtable )
 1227+ && !is_array( $unidtable[$v] )
 1228+ && $to
 1229+ && in_array( $v, $variants ) ) {
 1230+ $unidtable[$v] = array( $from => $to );
 1231+ } elseif ( $to && in_array( $v, $variants ) ) {
 1232+ $unidtable[$v][$from] = $to;
 1233+ }
 1234+ }
 1235+ // syntax error, pass
 1236+ if ( !isset( $this->mConverter->mVariantNames[$v] ) ) {
 1237+ $bidtable = array();
 1238+ $unidtable = array();
 1239+ break;
 1240+ }
 1241+ }
 1242+ $this->mBidtable = $bidtable;
 1243+ $this->mUnidtable = $unidtable;
 1244+ }
 1245+
 1246+ /**
 1247+ * @private
 1248+ *
 1249+ * @return string
 1250+ */
 1251+ function getRulesDesc() {
 1252+ $codesep = $this->mConverter->mDescCodeSep;
 1253+ $varsep = $this->mConverter->mDescVarSep;
 1254+ $text = '';
 1255+ foreach ( $this->mBidtable as $k => $v ) {
 1256+ $text .= $this->mConverter->mVariantNames[$k] . "$codesep$v$varsep";
 1257+ }
 1258+ foreach ( $this->mUnidtable as $k => $a ) {
 1259+ foreach ( $a as $from => $to ) {
 1260+ $text .= $from . '⇒' . $this->mConverter->mVariantNames[$k] .
 1261+ "$codesep$to$varsep";
 1262+ }
 1263+ }
 1264+ return $text;
 1265+ }
 1266+
 1267+ /**
 1268+ * Parse rules conversion.
 1269+ * @private
 1270+ *
 1271+ * @param $variant
 1272+ *
 1273+ * @return string
 1274+ */
 1275+ function getRuleConvertedStr( $variant ) {
 1276+ $bidtable = $this->mBidtable;
 1277+ $unidtable = $this->mUnidtable;
 1278+
 1279+ if ( count( $bidtable ) + count( $unidtable ) == 0 ) {
 1280+ return $this->mRules;
 1281+ } else {
 1282+ // display current variant in bidirectional array
 1283+ $disp = $this->getTextInBidtable( $variant );
 1284+ // or display current variant in fallbacks
 1285+ if ( !$disp ) {
 1286+ $disp = $this->getTextInBidtable(
 1287+ $this->mConverter->getVariantFallbacks( $variant ) );
 1288+ }
 1289+ // or display current variant in unidirectional array
 1290+ if ( !$disp && array_key_exists( $variant, $unidtable ) ) {
 1291+ $disp = array_values( $unidtable[$variant] );
 1292+ $disp = $disp[0];
 1293+ }
 1294+ // or display frist text under disable manual convert
 1295+ if ( !$disp
 1296+ && $this->mConverter->mManualLevel[$variant] == 'disable' ) {
 1297+ if ( count( $bidtable ) > 0 ) {
 1298+ $disp = array_values( $bidtable );
 1299+ $disp = $disp[0];
 1300+ } else {
 1301+ $disp = array_values( $unidtable );
 1302+ $disp = array_values( $disp[0] );
 1303+ $disp = $disp[0];
 1304+ }
 1305+ }
 1306+ return $disp;
 1307+ }
 1308+ }
 1309+
 1310+ /**
 1311+ * Generate conversion table for all text.
 1312+ * @private
 1313+ */
 1314+ function generateConvTable() {
 1315+ // Special case optimisation
 1316+ if ( !$this->mBidtable && !$this->mUnidtable ) {
 1317+ $this->mConvTable = array();
 1318+ return;
 1319+ }
 1320+
 1321+ $bidtable = $this->mBidtable;
 1322+ $unidtable = $this->mUnidtable;
 1323+ $manLevel = $this->mConverter->mManualLevel;
 1324+
 1325+ $vmarked = array();
 1326+ foreach ( $this->mConverter->mVariants as $v ) {
 1327+ /* for bidirectional array
 1328+ fill in the missing variants, if any,
 1329+ with fallbacks */
 1330+ if ( !isset( $bidtable[$v] ) ) {
 1331+ $variantFallbacks =
 1332+ $this->mConverter->getVariantFallbacks( $v );
 1333+ $vf = $this->getTextInBidtable( $variantFallbacks );
 1334+ if ( $vf ) {
 1335+ $bidtable[$v] = $vf;
 1336+ }
 1337+ }
 1338+
 1339+ if ( isset( $bidtable[$v] ) ) {
 1340+ foreach ( $vmarked as $vo ) {
 1341+ // use syntax: -{A|zh:WordZh;zh-tw:WordTw}-
 1342+ // or -{H|zh:WordZh;zh-tw:WordTw}-
 1343+ // or -{-|zh:WordZh;zh-tw:WordTw}-
 1344+ // to introduce a custom mapping between
 1345+ // words WordZh and WordTw in the whole text
 1346+ if ( $manLevel[$v] == 'bidirectional' ) {
 1347+ $this->mConvTable[$v][$bidtable[$vo]] = $bidtable[$v];
 1348+ }
 1349+ if ( $manLevel[$vo] == 'bidirectional' ) {
 1350+ $this->mConvTable[$vo][$bidtable[$v]] = $bidtable[$vo];
 1351+ }
 1352+ }
 1353+ $vmarked[] = $v;
 1354+ }
 1355+ /* for unidirectional array fill to convert tables */
 1356+ if ( ( $manLevel[$v] == 'bidirectional' || $manLevel[$v] == 'unidirectional' )
 1357+ && isset( $unidtable[$v] ) )
 1358+ {
 1359+ if ( isset( $this->mConvTable[$v] ) ) {
 1360+ $this->mConvTable[$v] = array_merge( $this->mConvTable[$v], $unidtable[$v] );
 1361+ } else {
 1362+ $this->mConvTable[$v] = $unidtable[$v];
 1363+ }
 1364+ }
 1365+ }
 1366+ }
 1367+
 1368+ /**
 1369+ * Parse rules and flags.
 1370+ * @param $variant String: variant language code
 1371+ */
 1372+ public function parse( $variant = null ) {
 1373+ if ( !$variant ) {
 1374+ $variant = $this->mConverter->getPreferredVariant();
 1375+ }
 1376+
 1377+ $this->parseFlags();
 1378+ $flags = $this->mFlags;
 1379+
 1380+ // convert to specified variant
 1381+ // syntax: -{zh-hans;zh-hant[;...]|<text to convert>}-
 1382+ if ( $this->mVariantFlags ) {
 1383+ // check if current variant in flags
 1384+ if ( isset( $this->mVariantFlags[$variant] ) ) {
 1385+ // then convert <text to convert> to current language
 1386+ $this->mRules = $this->mConverter->autoConvert( $this->mRules,
 1387+ $variant );
 1388+ } else { // if current variant no in flags,
 1389+ // then we check its fallback variants.
 1390+ $variantFallbacks =
 1391+ $this->mConverter->getVariantFallbacks( $variant );
 1392+ foreach ( $variantFallbacks as $variantFallback ) {
 1393+ // if current variant's fallback exist in flags
 1394+ if ( isset( $this->mVariantFlags[$variantFallback] ) ) {
 1395+ // then convert <text to convert> to fallback language
 1396+ $this->mRules =
 1397+ $this->mConverter->autoConvert( $this->mRules,
 1398+ $variantFallback );
 1399+ break;
 1400+ }
 1401+ }
 1402+ }
 1403+ $this->mFlags = $flags = array( 'R' => true );
 1404+ }
 1405+
 1406+ if ( !isset( $flags['R'] ) && !isset( $flags['N'] ) ) {
 1407+ // decode => HTML entities modified by Sanitizer::removeHTMLtags
 1408+ $this->mRules = str_replace( '=&gt;', '=>', $this->mRules );
 1409+ $this->parseRules();
 1410+ }
 1411+ $rules = $this->mRules;
 1412+
 1413+ if ( !$this->mBidtable && !$this->mUnidtable ) {
 1414+ if ( isset( $flags['+'] ) || isset( $flags['-'] ) ) {
 1415+ // fill all variants if text in -{A/H/-|text} without rules
 1416+ foreach ( $this->mConverter->mVariants as $v ) {
 1417+ $this->mBidtable[$v] = $rules;
 1418+ }
 1419+ } elseif ( !isset( $flags['N'] ) && !isset( $flags['T'] ) ) {
 1420+ $this->mFlags = $flags = array( 'R' => true );
 1421+ }
 1422+ }
 1423+
 1424+ $this->mRuleDisplay = false;
 1425+ foreach ( $flags as $flag => $unused ) {
 1426+ switch ( $flag ) {
 1427+ case 'R':
 1428+ // if we don't do content convert, still strip the -{}- tags
 1429+ $this->mRuleDisplay = $rules;
 1430+ break;
 1431+ case 'N':
 1432+ // process N flag: output current variant name
 1433+ $ruleVar = trim( $rules );
 1434+ if ( isset( $this->mConverter->mVariantNames[$ruleVar] ) ) {
 1435+ $this->mRuleDisplay = $this->mConverter->mVariantNames[$ruleVar];
 1436+ } else {
 1437+ $this->mRuleDisplay = '';
 1438+ }
 1439+ break;
 1440+ case 'D':
 1441+ // process D flag: output rules description
 1442+ $this->mRuleDisplay = $this->getRulesDesc();
 1443+ break;
 1444+ case 'H':
 1445+ // process H,- flag or T only: output nothing
 1446+ $this->mRuleDisplay = '';
 1447+ break;
 1448+ case '-':
 1449+ $this->mRulesAction = 'remove';
 1450+ $this->mRuleDisplay = '';
 1451+ break;
 1452+ case '+':
 1453+ $this->mRulesAction = 'add';
 1454+ $this->mRuleDisplay = '';
 1455+ break;
 1456+ case 'S':
 1457+ $this->mRuleDisplay = $this->getRuleConvertedStr( $variant );
 1458+ break;
 1459+ case 'T':
 1460+ $this->mRuleTitle = $this->getRuleConvertedStr( $variant );
 1461+ $this->mRuleDisplay = '';
 1462+ break;
 1463+ default:
 1464+ // ignore unknown flags (but see error case below)
 1465+ }
 1466+ }
 1467+ if ( $this->mRuleDisplay === false ) {
 1468+ $this->mRuleDisplay = $this->mManualCodeError;
 1469+ }
 1470+
 1471+ $this->generateConvTable();
 1472+ }
 1473+
 1474+ /**
 1475+ * @todo FIXME: code this function :)
 1476+ */
 1477+ public function hasRules() {
 1478+ // TODO:
 1479+ }
 1480+
 1481+ /**
 1482+ * Get display text on markup -{...}-
 1483+ * @return string
 1484+ */
 1485+ public function getDisplay() {
 1486+ return $this->mRuleDisplay;
 1487+ }
 1488+
 1489+ /**
 1490+ * Get converted title.
 1491+ * @return string
 1492+ */
 1493+ public function getTitle() {
 1494+ return $this->mRuleTitle;
 1495+ }
 1496+
 1497+ /**
 1498+ * Return how deal with conversion rules.
 1499+ * @return string
 1500+ */
 1501+ public function getRulesAction() {
 1502+ return $this->mRulesAction;
 1503+ }
 1504+
 1505+ /**
 1506+ * Get conversion table. (bidirectional and unidirectional
 1507+ * conversion table)
 1508+ * @return array
 1509+ */
 1510+ public function getConvTable() {
 1511+ return $this->mConvTable;
 1512+ }
 1513+
 1514+ /**
 1515+ * Get conversion rules string.
 1516+ * @return string
 1517+ */
 1518+ public function getRules() {
 1519+ return $this->mRules;
 1520+ }
 1521+
 1522+ /**
 1523+ * Get conversion flags.
 1524+ * @return array
 1525+ */
 1526+ public function getFlags() {
 1527+ return $this->mFlags;
 1528+ }
 1529+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageConverter.php
___________________________________________________________________
Added: svn:eol-style
11530 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageDsb.php
@@ -0,0 +1,51 @@
 2+<?php
 3+
 4+/** Lower Sorbian (Dolnoserbski)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageDsb extends Language {
 9+
 10+ /**
 11+ * Convert from the nominative form of a noun to some other case
 12+ * Invoked with {{grammar:case|word}}
 13+ *
 14+ * @param $word string
 15+ * @param $case string
 16+ * @return string
 17+ */
 18+ function convertGrammar( $word, $case ) {
 19+ global $wgGrammarForms;
 20+ if ( isset( $wgGrammarForms['dsb'][$case][$word] ) ) {
 21+ return $wgGrammarForms['dsb'][$case][$word];
 22+ }
 23+
 24+ switch ( $case ) {
 25+ case 'instrumental': # instrumental
 26+ $word = 'z ' . $word;
 27+ case 'lokatiw': # lokatiw
 28+ $word = 'wo ' . $word;
 29+ break;
 30+ }
 31+
 32+ return $word; # this will return the original value for 'nominatiw' (nominativ) and all undefined case values
 33+ }
 34+
 35+ /**
 36+ * @param $count int
 37+ * @param $forms array
 38+ * @return string
 39+ */
 40+ function convertPlural( $count, $forms ) {
 41+ if ( !count( $forms ) ) { return ''; }
 42+ $forms = $this->preConvertPlural( $forms, 4 );
 43+
 44+ switch ( abs( $count ) % 100 ) {
 45+ case 1: return $forms[0]; // singular
 46+ case 2: return $forms[1]; // dual
 47+ case 3:
 48+ case 4: return $forms[2]; // plural
 49+ default: return $forms[3]; // pluralgen
 50+ }
 51+ }
 52+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageDsb.php
___________________________________________________________________
Added: svn:eol-style
153 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageHsb.php
@@ -0,0 +1,52 @@
 2+<?php
 3+/** Upper Sorbian (Hornjoserbsce)
 4+ *
 5+ * @ingroup Language
 6+ */
 7+
 8+class LanguageHsb extends Language {
 9+
 10+ /**
 11+ * Convert from the nominative form of a noun to some other case
 12+ * Invoked with {{grammar:case|word}}
 13+ *
 14+ * @param $word string
 15+ * @param $case string
 16+ * @return string
 17+ */
 18+ function convertGrammar( $word, $case ) {
 19+ global $wgGrammarForms;
 20+ if ( isset( $wgGrammarForms['hsb'][$case][$word] ) ) {
 21+ return $wgGrammarForms['hsb'][$case][$word];
 22+ }
 23+
 24+ switch ( $case ) {
 25+ case 'instrumental': # instrumental
 26+ $word = 'z ' . $word;
 27+ break;
 28+ case 'lokatiw': # lokatiw
 29+ $word = 'wo ' . $word;
 30+ break;
 31+ }
 32+
 33+ return $word; # this will return the original value for 'nominatiw' (nominativ) and all undefined case values
 34+ }
 35+
 36+ /**
 37+ * @param $count int
 38+ * @param $forms array
 39+ * @return string
 40+ */
 41+ function convertPlural( $count, $forms ) {
 42+ if ( !count( $forms ) ) { return ''; }
 43+ $forms = $this->preConvertPlural( $forms, 4 );
 44+
 45+ switch ( abs( $count ) % 100 ) {
 46+ case 1: return $forms[0]; // singular
 47+ case 2: return $forms[1]; // dual
 48+ case 3:
 49+ case 4: return $forms[2]; // plural
 50+ default: return $forms[3]; // pluralgen
 51+ }
 52+ }
 53+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageHsb.php
___________________________________________________________________
Added: svn:eol-style
154 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageKu_ku.php
@@ -0,0 +1,24 @@
 2+<?php
 3+
 4+/** Kurdish
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageKu_ku extends Language {
 9+
 10+ /**
 11+ * Avoid grouping whole numbers between 0 to 9999
 12+ *
 13+ * @param $_ string
 14+ *
 15+ * @return string
 16+ */
 17+ function commafy( $_ ) {
 18+
 19+ if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
 20+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 21+ } else {
 22+ return $_;
 23+ }
 24+ }
 25+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageKu_ku.php
___________________________________________________________________
Added: svn:eol-style
126 + native
Index: trunk/tools/ToolserverI18N/language/classes/Language.php
@@ -0,0 +1,3527 @@
 2+<?php
 3+/**
 4+ * Internationalisation code
 5+ *
 6+ * @file
 7+ * @ingroup Language
 8+ */
 9+
 10+/**
 11+ * @defgroup Language Language
 12+ */
 13+
 14+if ( !defined( 'TS_INTUITION' ) ) {
 15+ echo "This file is part of Toolserver Intuition, it is not a valid entry point.\n";
 16+ exit( 1 );
 17+}
 18+
 19+# Read language names
 20+global $wgLanguageNames;
 21+require_once( dirname( __FILE__ ) . '/Names.php' );
 22+
 23+if ( function_exists( 'mb_strtoupper' ) ) {
 24+ mb_internal_encoding( 'UTF-8' );
 25+}
 26+
 27+/**
 28+ * a fake language converter
 29+ *
 30+ * @ingroup Language
 31+ */
 32+class FakeConverter {
 33+ var $mLang;
 34+ function __construct( $langobj ) { $this->mLang = $langobj; }
 35+ function autoConvertToAllVariants( $text ) { return array( $this->mLang->getCode() => $text ); }
 36+ function convert( $t ) { return $t; }
 37+ function convertTitle( $t ) { return $t->getPrefixedText(); }
 38+ function getVariants() { return array( $this->mLang->getCode() ); }
 39+ function getPreferredVariant() { return $this->mLang->getCode(); }
 40+ function getDefaultVariant() { return $this->mLang->getCode(); }
 41+ function getURLVariant() { return ''; }
 42+ function getConvRuleTitle() { return false; }
 43+ function findVariantLink( &$l, &$n, $ignoreOtherCond = false ) { }
 44+ function getExtraHashOptions() { return ''; }
 45+ function getParsedTitle() { return ''; }
 46+ function markNoConversion( $text, $noParse = false ) { return $text; }
 47+ function convertCategoryKey( $key ) { return $key; }
 48+ function convertLinkToAllVariants( $text ) { return $this->autoConvertToAllVariants( $text ); }
 49+ function armourMath( $text ) { return $text; }
 50+}
 51+
 52+/**
 53+ * Internationalisation code
 54+ * @ingroup Language
 55+ */
 56+class Language {
 57+ var $mConverter, $mVariants, $mCode, $mLoaded = false;
 58+ var $mMagicExtensions = array(), $mMagicHookDone = false;
 59+
 60+ var $mNamespaceIds, $namespaceNames, $namespaceAliases;
 61+ var $dateFormatStrings = array();
 62+ var $mExtendedSpecialPageAliases;
 63+
 64+ /**
 65+ * ReplacementArray object caches
 66+ */
 67+ var $transformData = array();
 68+
 69+ /**
 70+ * @var LocalisationCache
 71+ */
 72+ static public $dataCache;
 73+
 74+ static public $mLangObjCache = array();
 75+
 76+ static public $mWeekdayMsgs = array(
 77+ 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
 78+ 'friday', 'saturday'
 79+ );
 80+
 81+ static public $mWeekdayAbbrevMsgs = array(
 82+ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'
 83+ );
 84+
 85+ static public $mMonthMsgs = array(
 86+ 'january', 'february', 'march', 'april', 'may_long', 'june',
 87+ 'july', 'august', 'september', 'october', 'november',
 88+ 'december'
 89+ );
 90+ static public $mMonthGenMsgs = array(
 91+ 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen',
 92+ 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen',
 93+ 'december-gen'
 94+ );
 95+ static public $mMonthAbbrevMsgs = array(
 96+ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug',
 97+ 'sep', 'oct', 'nov', 'dec'
 98+ );
 99+
 100+ static public $mIranianCalendarMonthMsgs = array(
 101+ 'iranian-calendar-m1', 'iranian-calendar-m2', 'iranian-calendar-m3',
 102+ 'iranian-calendar-m4', 'iranian-calendar-m5', 'iranian-calendar-m6',
 103+ 'iranian-calendar-m7', 'iranian-calendar-m8', 'iranian-calendar-m9',
 104+ 'iranian-calendar-m10', 'iranian-calendar-m11', 'iranian-calendar-m12'
 105+ );
 106+
 107+ static public $mHebrewCalendarMonthMsgs = array(
 108+ 'hebrew-calendar-m1', 'hebrew-calendar-m2', 'hebrew-calendar-m3',
 109+ 'hebrew-calendar-m4', 'hebrew-calendar-m5', 'hebrew-calendar-m6',
 110+ 'hebrew-calendar-m7', 'hebrew-calendar-m8', 'hebrew-calendar-m9',
 111+ 'hebrew-calendar-m10', 'hebrew-calendar-m11', 'hebrew-calendar-m12',
 112+ 'hebrew-calendar-m6a', 'hebrew-calendar-m6b'
 113+ );
 114+
 115+ static public $mHebrewCalendarMonthGenMsgs = array(
 116+ 'hebrew-calendar-m1-gen', 'hebrew-calendar-m2-gen', 'hebrew-calendar-m3-gen',
 117+ 'hebrew-calendar-m4-gen', 'hebrew-calendar-m5-gen', 'hebrew-calendar-m6-gen',
 118+ 'hebrew-calendar-m7-gen', 'hebrew-calendar-m8-gen', 'hebrew-calendar-m9-gen',
 119+ 'hebrew-calendar-m10-gen', 'hebrew-calendar-m11-gen', 'hebrew-calendar-m12-gen',
 120+ 'hebrew-calendar-m6a-gen', 'hebrew-calendar-m6b-gen'
 121+ );
 122+
 123+ static public $mHijriCalendarMonthMsgs = array(
 124+ 'hijri-calendar-m1', 'hijri-calendar-m2', 'hijri-calendar-m3',
 125+ 'hijri-calendar-m4', 'hijri-calendar-m5', 'hijri-calendar-m6',
 126+ 'hijri-calendar-m7', 'hijri-calendar-m8', 'hijri-calendar-m9',
 127+ 'hijri-calendar-m10', 'hijri-calendar-m11', 'hijri-calendar-m12'
 128+ );
 129+
 130+ /**
 131+ * Get a cached language object for a given language code
 132+ * @param $code String
 133+ * @return Language
 134+ */
 135+ static function factory( $code ) {
 136+ if ( !isset( self::$mLangObjCache[$code] ) ) {
 137+ if ( count( self::$mLangObjCache ) > 10 ) {
 138+ // Don't keep a billion objects around, that's stupid.
 139+ self::$mLangObjCache = array();
 140+ }
 141+ self::$mLangObjCache[$code] = self::newFromCode( $code );
 142+ }
 143+ return self::$mLangObjCache[$code];
 144+ }
 145+
 146+ /**
 147+ * Create a language object for a given language code
 148+ * @param $code String
 149+ * @return Language
 150+ */
 151+ protected static function newFromCode( $code ) {
 152+ global $IP;
 153+ static $recursionLevel = 0;
 154+
 155+ // Protect against path traversal below
 156+ if ( !Language::isValidCode( $code )
 157+ || strcspn( $code, ":/\\\000" ) !== strlen( $code ) )
 158+ {
 159+ throw new MWException( "Invalid language code \"$code\"" );
 160+ }
 161+
 162+ if ( !Language::isValidBuiltInCode( $code ) ) {
 163+ // It's not possible to customise this code with class files, so
 164+ // just return a Language object. This is to support uselang= hacks.
 165+ $lang = new Language;
 166+ $lang->setCode( $code );
 167+ return $lang;
 168+ }
 169+
 170+ if ( $code == 'en' ) {
 171+ $class = 'Language';
 172+ } else {
 173+ $class = 'Language' . str_replace( '-', '_', ucfirst( $code ) );
 174+ if ( !defined( 'MW_COMPILED' ) ) {
 175+ // Preload base classes to work around APC/PHP5 bug
 176+ if ( file_exists( "$IP/languages/classes/$class.deps.php" ) ) {
 177+ include_once( "$IP/languages/classes/$class.deps.php" );
 178+ }
 179+ if ( file_exists( "$IP/languages/classes/$class.php" ) ) {
 180+ include_once( "$IP/languages/classes/$class.php" );
 181+ }
 182+ }
 183+ }
 184+
 185+ if ( $recursionLevel > 5 ) {
 186+ throw new MWException( "Language fallback loop detected when creating class $class\n" );
 187+ }
 188+
 189+ if ( !MWInit::classExists( $class ) ) {
 190+ $fallback = Language::getFallbackFor( $code );
 191+ ++$recursionLevel;
 192+ $lang = Language::newFromCode( $fallback );
 193+ --$recursionLevel;
 194+ $lang->setCode( $code );
 195+ } else {
 196+ $lang = new $class;
 197+ }
 198+ return $lang;
 199+ }
 200+
 201+ /**
 202+ * Returns true if a language code string is of a valid form, whether or
 203+ * not it exists. This includes codes which are used solely for
 204+ * customisation via the MediaWiki namespace.
 205+ *
 206+ * @param $code string
 207+ *
 208+ * @return bool
 209+ */
 210+ public static function isValidCode( $code ) {
 211+ return
 212+ strcspn( $code, ":/\\\000" ) === strlen( $code )
 213+ && !preg_match( Title::getTitleInvalidRegex(), $code );
 214+ }
 215+
 216+ /**
 217+ * Returns true if a language code is of a valid form for the purposes of
 218+ * internal customisation of MediaWiki, via Messages*.php.
 219+ *
 220+ * @param $code string
 221+ *
 222+ * @return bool
 223+ */
 224+ public static function isValidBuiltInCode( $code ) {
 225+ return preg_match( '/^[a-z0-9-]*$/i', $code );
 226+ }
 227+
 228+ /**
 229+ * Get the LocalisationCache instance
 230+ *
 231+ * @return LocalisationCache
 232+ */
 233+ public static function getLocalisationCache() {
 234+ if ( is_null( self::$dataCache ) ) {
 235+ global $wgLocalisationCacheConf;
 236+ $class = $wgLocalisationCacheConf['class'];
 237+ self::$dataCache = new $class( $wgLocalisationCacheConf );
 238+ }
 239+ return self::$dataCache;
 240+ }
 241+
 242+ function __construct() {
 243+ // Set the code to the name of the descendant
 244+ if ( get_class( $this ) == 'Language' ) {
 245+ $this->mCode = 'en';
 246+ } else {
 247+ $this->mCode = str_replace( '_', '-', strtolower( substr( get_class( $this ), 8 ) ) );
 248+ }
 249+ }
 250+
 251+ /**
 252+ * Reduce memory usage
 253+ */
 254+ function __destruct() {
 255+ foreach ( $this as $name => $value ) {
 256+ unset( $this->$name );
 257+ }
 258+ }
 259+
 260+ /**
 261+ * Hook which will be called if this is the content language.
 262+ * Descendants can use this to register hook functions or modify globals
 263+ */
 264+ function initContLang() { }
 265+
 266+ /**
 267+ * @return array|bool
 268+ */
 269+ function getFallbackLanguageCode() {
 270+ if ( $this->mCode === 'en' ) {
 271+ return false;
 272+ } else {
 273+ return self::$dataCache->getItem( $this->mCode, 'fallback' );
 274+ }
 275+ }
 276+
 277+ /**
 278+ * Exports $wgBookstoreListEn
 279+ * @return array
 280+ */
 281+ function getBookstoreList() {
 282+ return self::$dataCache->getItem( $this->mCode, 'bookstoreList' );
 283+ }
 284+
 285+ /**
 286+ * @return array
 287+ */
 288+ function getNamespaces() {
 289+ if ( is_null( $this->namespaceNames ) ) {
 290+ global $wgMetaNamespace, $wgMetaNamespaceTalk, $wgExtraNamespaces;
 291+
 292+ $this->namespaceNames = self::$dataCache->getItem( $this->mCode, 'namespaceNames' );
 293+ $validNamespaces = MWNamespace::getCanonicalNamespaces();
 294+
 295+ $this->namespaceNames = $wgExtraNamespaces + $this->namespaceNames + $validNamespaces;
 296+
 297+ $this->namespaceNames[NS_PROJECT] = $wgMetaNamespace;
 298+ if ( $wgMetaNamespaceTalk ) {
 299+ $this->namespaceNames[NS_PROJECT_TALK] = $wgMetaNamespaceTalk;
 300+ } else {
 301+ $talk = $this->namespaceNames[NS_PROJECT_TALK];
 302+ $this->namespaceNames[NS_PROJECT_TALK] =
 303+ $this->fixVariableInNamespace( $talk );
 304+ }
 305+
 306+ # Sometimes a language will be localised but not actually exist on this wiki.
 307+ foreach( $this->namespaceNames as $key => $text ) {
 308+ if ( !isset( $validNamespaces[$key] ) ) {
 309+ unset( $this->namespaceNames[$key] );
 310+ }
 311+ }
 312+
 313+ # The above mixing may leave namespaces out of canonical order.
 314+ # Re-order by namespace ID number...
 315+ ksort( $this->namespaceNames );
 316+ }
 317+ return $this->namespaceNames;
 318+ }
 319+
 320+ /**
 321+ * A convenience function that returns the same thing as
 322+ * getNamespaces() except with the array values changed to ' '
 323+ * where it found '_', useful for producing output to be displayed
 324+ * e.g. in <select> forms.
 325+ *
 326+ * @return array
 327+ */
 328+ function getFormattedNamespaces() {
 329+ $ns = $this->getNamespaces();
 330+ foreach ( $ns as $k => $v ) {
 331+ $ns[$k] = strtr( $v, '_', ' ' );
 332+ }
 333+ return $ns;
 334+ }
 335+
 336+ /**
 337+ * Get a namespace value by key
 338+ * <code>
 339+ * $mw_ns = $wgContLang->getNsText( NS_MEDIAWIKI );
 340+ * echo $mw_ns; // prints 'MediaWiki'
 341+ * </code>
 342+ *
 343+ * @param $index Int: the array key of the namespace to return
 344+ * @return mixed, string if the namespace value exists, otherwise false
 345+ */
 346+ function getNsText( $index ) {
 347+ $ns = $this->getNamespaces();
 348+ return isset( $ns[$index] ) ? $ns[$index] : false;
 349+ }
 350+
 351+ /**
 352+ * A convenience function that returns the same thing as
 353+ * getNsText() except with '_' changed to ' ', useful for
 354+ * producing output.
 355+ *
 356+ * @param $index string
 357+ *
 358+ * @return array
 359+ */
 360+ function getFormattedNsText( $index ) {
 361+ $ns = $this->getNsText( $index );
 362+ return strtr( $ns, '_', ' ' );
 363+ }
 364+
 365+ /**
 366+ * Returns gender-dependent namespace alias if available.
 367+ * @param $index Int: namespace index
 368+ * @param $gender String: gender key (male, female... )
 369+ * @return String
 370+ * @since 1.18
 371+ */
 372+ function getGenderNsText( $index, $gender ) {
 373+ $ns = self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
 374+ return isset( $ns[$index][$gender] ) ? $ns[$index][$gender] : $this->getNsText( $index );
 375+ }
 376+
 377+ /**
 378+ * Whether this language makes distinguishes genders for example in
 379+ * namespaces.
 380+ * @return bool
 381+ * @since 1.18
 382+ */
 383+ function needsGenderDistinction() {
 384+ $aliases = self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
 385+ return count( $aliases ) > 0;
 386+ }
 387+
 388+ /**
 389+ * Get a namespace key by value, case insensitive.
 390+ * Only matches namespace names for the current language, not the
 391+ * canonical ones defined in Namespace.php.
 392+ *
 393+ * @param $text String
 394+ * @return mixed An integer if $text is a valid value otherwise false
 395+ */
 396+ function getLocalNsIndex( $text ) {
 397+ $lctext = $this->lc( $text );
 398+ $ids = $this->getNamespaceIds();
 399+ return isset( $ids[$lctext] ) ? $ids[$lctext] : false;
 400+ }
 401+
 402+ /**
 403+ * @return array
 404+ */
 405+ function getNamespaceAliases() {
 406+ if ( is_null( $this->namespaceAliases ) ) {
 407+ $aliases = self::$dataCache->getItem( $this->mCode, 'namespaceAliases' );
 408+ if ( !$aliases ) {
 409+ $aliases = array();
 410+ } else {
 411+ foreach ( $aliases as $name => $index ) {
 412+ if ( $index === NS_PROJECT_TALK ) {
 413+ unset( $aliases[$name] );
 414+ $name = $this->fixVariableInNamespace( $name );
 415+ $aliases[$name] = $index;
 416+ }
 417+ }
 418+ }
 419+
 420+ $genders = self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
 421+ foreach ( $genders as $index => $forms ) {
 422+ foreach ( $forms as $alias ) {
 423+ $aliases[$alias] = $index;
 424+ }
 425+ }
 426+
 427+ $this->namespaceAliases = $aliases;
 428+ }
 429+ return $this->namespaceAliases;
 430+ }
 431+
 432+ /**
 433+ * @return array
 434+ */
 435+ function getNamespaceIds() {
 436+ if ( is_null( $this->mNamespaceIds ) ) {
 437+ global $wgNamespaceAliases;
 438+ # Put namespace names and aliases into a hashtable.
 439+ # If this is too slow, then we should arrange it so that it is done
 440+ # before caching. The catch is that at pre-cache time, the above
 441+ # class-specific fixup hasn't been done.
 442+ $this->mNamespaceIds = array();
 443+ foreach ( $this->getNamespaces() as $index => $name ) {
 444+ $this->mNamespaceIds[$this->lc( $name )] = $index;
 445+ }
 446+ foreach ( $this->getNamespaceAliases() as $name => $index ) {
 447+ $this->mNamespaceIds[$this->lc( $name )] = $index;
 448+ }
 449+ if ( $wgNamespaceAliases ) {
 450+ foreach ( $wgNamespaceAliases as $name => $index ) {
 451+ $this->mNamespaceIds[$this->lc( $name )] = $index;
 452+ }
 453+ }
 454+ }
 455+ return $this->mNamespaceIds;
 456+ }
 457+
 458+
 459+ /**
 460+ * Get a namespace key by value, case insensitive. Canonical namespace
 461+ * names override custom ones defined for the current language.
 462+ *
 463+ * @param $text String
 464+ * @return mixed An integer if $text is a valid value otherwise false
 465+ */
 466+ function getNsIndex( $text ) {
 467+ $lctext = $this->lc( $text );
 468+ if ( ( $ns = MWNamespace::getCanonicalIndex( $lctext ) ) !== null ) {
 469+ return $ns;
 470+ }
 471+ $ids = $this->getNamespaceIds();
 472+ return isset( $ids[$lctext] ) ? $ids[$lctext] : false;
 473+ }
 474+
 475+ /**
 476+ * short names for language variants used for language conversion links.
 477+ *
 478+ * @param $code String
 479+ * @return string
 480+ */
 481+ function getVariantname( $code ) {
 482+ return $this->getMessageFromDB( "variantname-$code" );
 483+ }
 484+
 485+ /**
 486+ * @param $name string
 487+ * @return string
 488+ */
 489+ function specialPage( $name ) {
 490+ $aliases = $this->getSpecialPageAliases();
 491+ if ( isset( $aliases[$name][0] ) ) {
 492+ $name = $aliases[$name][0];
 493+ }
 494+ return $this->getNsText( NS_SPECIAL ) . ':' . $name;
 495+ }
 496+
 497+ /**
 498+ * @return array
 499+ */
 500+ function getQuickbarSettings() {
 501+ return array(
 502+ $this->getMessage( 'qbsettings-none' ),
 503+ $this->getMessage( 'qbsettings-fixedleft' ),
 504+ $this->getMessage( 'qbsettings-fixedright' ),
 505+ $this->getMessage( 'qbsettings-floatingleft' ),
 506+ $this->getMessage( 'qbsettings-floatingright' )
 507+ );
 508+ }
 509+
 510+ /**
 511+ * @return array
 512+ */
 513+ function getDatePreferences() {
 514+ return self::$dataCache->getItem( $this->mCode, 'datePreferences' );
 515+ }
 516+
 517+ /**
 518+ * @return array
 519+ */
 520+ function getDateFormats() {
 521+ return self::$dataCache->getItem( $this->mCode, 'dateFormats' );
 522+ }
 523+
 524+ /**
 525+ * @return array|string
 526+ */
 527+ function getDefaultDateFormat() {
 528+ $df = self::$dataCache->getItem( $this->mCode, 'defaultDateFormat' );
 529+ if ( $df === 'dmy or mdy' ) {
 530+ global $wgAmericanDates;
 531+ return $wgAmericanDates ? 'mdy' : 'dmy';
 532+ } else {
 533+ return $df;
 534+ }
 535+ }
 536+
 537+ /**
 538+ * @return array
 539+ */
 540+ function getDatePreferenceMigrationMap() {
 541+ return self::$dataCache->getItem( $this->mCode, 'datePreferenceMigrationMap' );
 542+ }
 543+
 544+ /**
 545+ * @param $image
 546+ * @return array|null
 547+ */
 548+ function getImageFile( $image ) {
 549+ return self::$dataCache->getSubitem( $this->mCode, 'imageFiles', $image );
 550+ }
 551+
 552+ /**
 553+ * @return array
 554+ */
 555+ function getDefaultUserOptionOverrides() {
 556+ return self::$dataCache->getItem( $this->mCode, 'defaultUserOptionOverrides' );
 557+ }
 558+
 559+ /**
 560+ * @return array
 561+ */
 562+ function getExtraUserToggles() {
 563+ return self::$dataCache->getItem( $this->mCode, 'extraUserToggles' );
 564+ }
 565+
 566+ /**
 567+ * @param $tog
 568+ * @return string
 569+ */
 570+ function getUserToggle( $tog ) {
 571+ return $this->getMessageFromDB( "tog-$tog" );
 572+ }
 573+
 574+ /**
 575+ * Get language names, indexed by code.
 576+ * If $customisedOnly is true, only returns codes with a messages file
 577+ *
 578+ * @param $customisedOnly bool
 579+ *
 580+ * @return array
 581+ */
 582+ public static function getLanguageNames( $customisedOnly = false ) {
 583+ global $wgExtraLanguageNames;
 584+ static $coreLanguageNames;
 585+
 586+ if ( $coreLanguageNames === null ) {
 587+ include( MWInit::compiledPath( 'languages/Names.php' ) );
 588+ }
 589+
 590+ $allNames = $wgExtraLanguageNames + $coreLanguageNames;
 591+ if ( !$customisedOnly ) {
 592+ return $allNames;
 593+ }
 594+
 595+ global $IP;
 596+ $names = array();
 597+ $dir = opendir( "$IP/languages/messages" );
 598+ while ( false !== ( $file = readdir( $dir ) ) ) {
 599+ $code = self::getCodeFromFileName( $file, 'Messages' );
 600+ if ( $code && isset( $allNames[$code] ) ) {
 601+ $names[$code] = $allNames[$code];
 602+ }
 603+ }
 604+ closedir( $dir );
 605+ return $names;
 606+ }
 607+
 608+ /**
 609+ * Get translated language names. This is done on best effort and
 610+ * by default this is exactly the same as Language::getLanguageNames.
 611+ * The CLDR extension provides translated names.
 612+ * @param $code String Language code.
 613+ * @return Array language code => language name
 614+ * @since 1.18.0
 615+ */
 616+ public static function getTranslatedLanguageNames( $code ) {
 617+ $names = array();
 618+ wfRunHooks( 'LanguageGetTranslatedLanguageNames', array( &$names, $code ) );
 619+
 620+ foreach ( self::getLanguageNames() as $code => $name ) {
 621+ if ( !isset( $names[$code] ) ) $names[$code] = $name;
 622+ }
 623+
 624+ return $names;
 625+ }
 626+
 627+ /**
 628+ * Get a message from the MediaWiki namespace.
 629+ *
 630+ * @param $msg String: message name
 631+ * @return string
 632+ */
 633+ function getMessageFromDB( $msg ) {
 634+ return wfMsgExt( $msg, array( 'parsemag', 'language' => $this ) );
 635+ }
 636+
 637+ /**
 638+ * @param $code string
 639+ * @return string
 640+ */
 641+ function getLanguageName( $code ) {
 642+ $names = self::getLanguageNames();
 643+ if ( !array_key_exists( $code, $names ) ) {
 644+ return '';
 645+ }
 646+ return $names[$code];
 647+ }
 648+
 649+ /**
 650+ * @param $key string
 651+ * @return string
 652+ */
 653+ function getMonthName( $key ) {
 654+ return $this->getMessageFromDB( self::$mMonthMsgs[$key - 1] );
 655+ }
 656+
 657+ /**
 658+ * @return array
 659+ */
 660+ function getMonthNamesArray() {
 661+ $monthNames = array( '' );
 662+ for ( $i=1; $i < 13; $i++ ) {
 663+ $monthNames[] = $this->getMonthName( $i );
 664+ }
 665+ return $monthNames;
 666+ }
 667+
 668+ /**
 669+ * @param $key string
 670+ * @return string
 671+ */
 672+ function getMonthNameGen( $key ) {
 673+ return $this->getMessageFromDB( self::$mMonthGenMsgs[$key - 1] );
 674+ }
 675+
 676+ /**
 677+ * @param $key string
 678+ * @return string
 679+ */
 680+ function getMonthAbbreviation( $key ) {
 681+ return $this->getMessageFromDB( self::$mMonthAbbrevMsgs[$key - 1] );
 682+ }
 683+
 684+ /**
 685+ * @return array
 686+ */
 687+ function getMonthAbbreviationsArray() {
 688+ $monthNames = array( '' );
 689+ for ( $i=1; $i < 13; $i++ ) {
 690+ $monthNames[] = $this->getMonthAbbreviation( $i );
 691+ }
 692+ return $monthNames;
 693+ }
 694+
 695+ /**
 696+ * @param $key string
 697+ * @return string
 698+ */
 699+ function getWeekdayName( $key ) {
 700+ return $this->getMessageFromDB( self::$mWeekdayMsgs[$key - 1] );
 701+ }
 702+
 703+ /**
 704+ * @param $key string
 705+ * @return string
 706+ */
 707+ function getWeekdayAbbreviation( $key ) {
 708+ return $this->getMessageFromDB( self::$mWeekdayAbbrevMsgs[$key - 1] );
 709+ }
 710+
 711+ /**
 712+ * @param $key string
 713+ * @return string
 714+ */
 715+ function getIranianCalendarMonthName( $key ) {
 716+ return $this->getMessageFromDB( self::$mIranianCalendarMonthMsgs[$key - 1] );
 717+ }
 718+
 719+ /**
 720+ * @param $key string
 721+ * @return string
 722+ */
 723+ function getHebrewCalendarMonthName( $key ) {
 724+ return $this->getMessageFromDB( self::$mHebrewCalendarMonthMsgs[$key - 1] );
 725+ }
 726+
 727+ /**
 728+ * @param $key string
 729+ * @return string
 730+ */
 731+ function getHebrewCalendarMonthNameGen( $key ) {
 732+ return $this->getMessageFromDB( self::$mHebrewCalendarMonthGenMsgs[$key - 1] );
 733+ }
 734+
 735+ /**
 736+ * @param $key string
 737+ * @return string
 738+ */
 739+ function getHijriCalendarMonthName( $key ) {
 740+ return $this->getMessageFromDB( self::$mHijriCalendarMonthMsgs[$key - 1] );
 741+ }
 742+
 743+ /**
 744+ * Used by date() and time() to adjust the time output.
 745+ *
 746+ * @param $ts Int the time in date('YmdHis') format
 747+ * @param $tz Mixed: adjust the time by this amount (default false, mean we
 748+ * get user timecorrection setting)
 749+ * @return int
 750+ */
 751+ function userAdjust( $ts, $tz = false ) {
 752+ global $wgUser, $wgLocalTZoffset;
 753+
 754+ if ( $tz === false ) {
 755+ $tz = $wgUser->getOption( 'timecorrection' );
 756+ }
 757+
 758+ $data = explode( '|', $tz, 3 );
 759+
 760+ if ( $data[0] == 'ZoneInfo' ) {
 761+ wfSuppressWarnings();
 762+ $userTZ = timezone_open( $data[2] );
 763+ wfRestoreWarnings();
 764+ if ( $userTZ !== false ) {
 765+ $date = date_create( $ts, timezone_open( 'UTC' ) );
 766+ date_timezone_set( $date, $userTZ );
 767+ $date = date_format( $date, 'YmdHis' );
 768+ return $date;
 769+ }
 770+ # Unrecognized timezone, default to 'Offset' with the stored offset.
 771+ $data[0] = 'Offset';
 772+ }
 773+
 774+ $minDiff = 0;
 775+ if ( $data[0] == 'System' || $tz == '' ) {
 776+ #  Global offset in minutes.
 777+ if ( isset( $wgLocalTZoffset ) ) {
 778+ $minDiff = $wgLocalTZoffset;
 779+ }
 780+ } elseif ( $data[0] == 'Offset' ) {
 781+ $minDiff = intval( $data[1] );
 782+ } else {
 783+ $data = explode( ':', $tz );
 784+ if ( count( $data ) == 2 ) {
 785+ $data[0] = intval( $data[0] );
 786+ $data[1] = intval( $data[1] );
 787+ $minDiff = abs( $data[0] ) * 60 + $data[1];
 788+ if ( $data[0] < 0 ) {
 789+ $minDiff = -$minDiff;
 790+ }
 791+ } else {
 792+ $minDiff = intval( $data[0] ) * 60;
 793+ }
 794+ }
 795+
 796+ # No difference ? Return time unchanged
 797+ if ( 0 == $minDiff ) {
 798+ return $ts;
 799+ }
 800+
 801+ wfSuppressWarnings(); // E_STRICT system time bitching
 802+ # Generate an adjusted date; take advantage of the fact that mktime
 803+ # will normalize out-of-range values so we don't have to split $minDiff
 804+ # into hours and minutes.
 805+ $t = mktime( (
 806+ (int)substr( $ts, 8, 2 ) ), # Hours
 807+ (int)substr( $ts, 10, 2 ) + $minDiff, # Minutes
 808+ (int)substr( $ts, 12, 2 ), # Seconds
 809+ (int)substr( $ts, 4, 2 ), # Month
 810+ (int)substr( $ts, 6, 2 ), # Day
 811+ (int)substr( $ts, 0, 4 ) ); # Year
 812+
 813+ $date = date( 'YmdHis', $t );
 814+ wfRestoreWarnings();
 815+
 816+ return $date;
 817+ }
 818+
 819+ /**
 820+ * This is a workalike of PHP's date() function, but with better
 821+ * internationalisation, a reduced set of format characters, and a better
 822+ * escaping format.
 823+ *
 824+ * Supported format characters are dDjlNwzWFmMntLoYyaAgGhHiscrU. See the
 825+ * PHP manual for definitions. There are a number of extensions, which
 826+ * start with "x":
 827+ *
 828+ * xn Do not translate digits of the next numeric format character
 829+ * xN Toggle raw digit (xn) flag, stays set until explicitly unset
 830+ * xr Use roman numerals for the next numeric format character
 831+ * xh Use hebrew numerals for the next numeric format character
 832+ * xx Literal x
 833+ * xg Genitive month name
 834+ *
 835+ * xij j (day number) in Iranian calendar
 836+ * xiF F (month name) in Iranian calendar
 837+ * xin n (month number) in Iranian calendar
 838+ * xiY Y (full year) in Iranian calendar
 839+ *
 840+ * xjj j (day number) in Hebrew calendar
 841+ * xjF F (month name) in Hebrew calendar
 842+ * xjt t (days in month) in Hebrew calendar
 843+ * xjx xg (genitive month name) in Hebrew calendar
 844+ * xjn n (month number) in Hebrew calendar
 845+ * xjY Y (full year) in Hebrew calendar
 846+ *
 847+ * xmj j (day number) in Hijri calendar
 848+ * xmF F (month name) in Hijri calendar
 849+ * xmn n (month number) in Hijri calendar
 850+ * xmY Y (full year) in Hijri calendar
 851+ *
 852+ * xkY Y (full year) in Thai solar calendar. Months and days are
 853+ * identical to the Gregorian calendar
 854+ * xoY Y (full year) in Minguo calendar or Juche year.
 855+ * Months and days are identical to the
 856+ * Gregorian calendar
 857+ * xtY Y (full year) in Japanese nengo. Months and days are
 858+ * identical to the Gregorian calendar
 859+ *
 860+ * Characters enclosed in double quotes will be considered literal (with
 861+ * the quotes themselves removed). Unmatched quotes will be considered
 862+ * literal quotes. Example:
 863+ *
 864+ * "The month is" F => The month is January
 865+ * i's" => 20'11"
 866+ *
 867+ * Backslash escaping is also supported.
 868+ *
 869+ * Input timestamp is assumed to be pre-normalized to the desired local
 870+ * time zone, if any.
 871+ *
 872+ * @param $format String
 873+ * @param $ts String: 14-character timestamp
 874+ * YYYYMMDDHHMMSS
 875+ * 01234567890123
 876+ * @todo handling of "o" format character for Iranian, Hebrew, Hijri & Thai?
 877+ *
 878+ * @return string
 879+ */
 880+ function sprintfDate( $format, $ts ) {
 881+ $s = '';
 882+ $raw = false;
 883+ $roman = false;
 884+ $hebrewNum = false;
 885+ $unix = false;
 886+ $rawToggle = false;
 887+ $iranian = false;
 888+ $hebrew = false;
 889+ $hijri = false;
 890+ $thai = false;
 891+ $minguo = false;
 892+ $tenno = false;
 893+ for ( $p = 0; $p < strlen( $format ); $p++ ) {
 894+ $num = false;
 895+ $code = $format[$p];
 896+ if ( $code == 'x' && $p < strlen( $format ) - 1 ) {
 897+ $code .= $format[++$p];
 898+ }
 899+
 900+ if ( ( $code === 'xi' || $code == 'xj' || $code == 'xk' || $code == 'xm' || $code == 'xo' || $code == 'xt' ) && $p < strlen( $format ) - 1 ) {
 901+ $code .= $format[++$p];
 902+ }
 903+
 904+ switch ( $code ) {
 905+ case 'xx':
 906+ $s .= 'x';
 907+ break;
 908+ case 'xn':
 909+ $raw = true;
 910+ break;
 911+ case 'xN':
 912+ $rawToggle = !$rawToggle;
 913+ break;
 914+ case 'xr':
 915+ $roman = true;
 916+ break;
 917+ case 'xh':
 918+ $hebrewNum = true;
 919+ break;
 920+ case 'xg':
 921+ $s .= $this->getMonthNameGen( substr( $ts, 4, 2 ) );
 922+ break;
 923+ case 'xjx':
 924+ if ( !$hebrew ) $hebrew = self::tsToHebrew( $ts );
 925+ $s .= $this->getHebrewCalendarMonthNameGen( $hebrew[1] );
 926+ break;
 927+ case 'd':
 928+ $num = substr( $ts, 6, 2 );
 929+ break;
 930+ case 'D':
 931+ if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts );
 932+ $s .= $this->getWeekdayAbbreviation( gmdate( 'w', $unix ) + 1 );
 933+ break;
 934+ case 'j':
 935+ $num = intval( substr( $ts, 6, 2 ) );
 936+ break;
 937+ case 'xij':
 938+ if ( !$iranian ) {
 939+ $iranian = self::tsToIranian( $ts );
 940+ }
 941+ $num = $iranian[2];
 942+ break;
 943+ case 'xmj':
 944+ if ( !$hijri ) {
 945+ $hijri = self::tsToHijri( $ts );
 946+ }
 947+ $num = $hijri[2];
 948+ break;
 949+ case 'xjj':
 950+ if ( !$hebrew ) {
 951+ $hebrew = self::tsToHebrew( $ts );
 952+ }
 953+ $num = $hebrew[2];
 954+ break;
 955+ case 'l':
 956+ if ( !$unix ) {
 957+ $unix = wfTimestamp( TS_UNIX, $ts );
 958+ }
 959+ $s .= $this->getWeekdayName( gmdate( 'w', $unix ) + 1 );
 960+ break;
 961+ case 'N':
 962+ if ( !$unix ) {
 963+ $unix = wfTimestamp( TS_UNIX, $ts );
 964+ }
 965+ $w = gmdate( 'w', $unix );
 966+ $num = $w ? $w : 7;
 967+ break;
 968+ case 'w':
 969+ if ( !$unix ) {
 970+ $unix = wfTimestamp( TS_UNIX, $ts );
 971+ }
 972+ $num = gmdate( 'w', $unix );
 973+ break;
 974+ case 'z':
 975+ if ( !$unix ) {
 976+ $unix = wfTimestamp( TS_UNIX, $ts );
 977+ }
 978+ $num = gmdate( 'z', $unix );
 979+ break;
 980+ case 'W':
 981+ if ( !$unix ) {
 982+ $unix = wfTimestamp( TS_UNIX, $ts );
 983+ }
 984+ $num = gmdate( 'W', $unix );
 985+ break;
 986+ case 'F':
 987+ $s .= $this->getMonthName( substr( $ts, 4, 2 ) );
 988+ break;
 989+ case 'xiF':
 990+ if ( !$iranian ) {
 991+ $iranian = self::tsToIranian( $ts );
 992+ }
 993+ $s .= $this->getIranianCalendarMonthName( $iranian[1] );
 994+ break;
 995+ case 'xmF':
 996+ if ( !$hijri ) {
 997+ $hijri = self::tsToHijri( $ts );
 998+ }
 999+ $s .= $this->getHijriCalendarMonthName( $hijri[1] );
 1000+ break;
 1001+ case 'xjF':
 1002+ if ( !$hebrew ) {
 1003+ $hebrew = self::tsToHebrew( $ts );
 1004+ }
 1005+ $s .= $this->getHebrewCalendarMonthName( $hebrew[1] );
 1006+ break;
 1007+ case 'm':
 1008+ $num = substr( $ts, 4, 2 );
 1009+ break;
 1010+ case 'M':
 1011+ $s .= $this->getMonthAbbreviation( substr( $ts, 4, 2 ) );
 1012+ break;
 1013+ case 'n':
 1014+ $num = intval( substr( $ts, 4, 2 ) );
 1015+ break;
 1016+ case 'xin':
 1017+ if ( !$iranian ) {
 1018+ $iranian = self::tsToIranian( $ts );
 1019+ }
 1020+ $num = $iranian[1];
 1021+ break;
 1022+ case 'xmn':
 1023+ if ( !$hijri ) {
 1024+ $hijri = self::tsToHijri ( $ts );
 1025+ }
 1026+ $num = $hijri[1];
 1027+ break;
 1028+ case 'xjn':
 1029+ if ( !$hebrew ) {
 1030+ $hebrew = self::tsToHebrew( $ts );
 1031+ }
 1032+ $num = $hebrew[1];
 1033+ break;
 1034+ case 't':
 1035+ if ( !$unix ) {
 1036+ $unix = wfTimestamp( TS_UNIX, $ts );
 1037+ }
 1038+ $num = gmdate( 't', $unix );
 1039+ break;
 1040+ case 'xjt':
 1041+ if ( !$hebrew ) {
 1042+ $hebrew = self::tsToHebrew( $ts );
 1043+ }
 1044+ $num = $hebrew[3];
 1045+ break;
 1046+ case 'L':
 1047+ if ( !$unix ) {
 1048+ $unix = wfTimestamp( TS_UNIX, $ts );
 1049+ }
 1050+ $num = gmdate( 'L', $unix );
 1051+ break;
 1052+ case 'o':
 1053+ if ( !$unix ) {
 1054+ $unix = wfTimestamp( TS_UNIX, $ts );
 1055+ }
 1056+ $num = date( 'o', $unix );
 1057+ break;
 1058+ case 'Y':
 1059+ $num = substr( $ts, 0, 4 );
 1060+ break;
 1061+ case 'xiY':
 1062+ if ( !$iranian ) {
 1063+ $iranian = self::tsToIranian( $ts );
 1064+ }
 1065+ $num = $iranian[0];
 1066+ break;
 1067+ case 'xmY':
 1068+ if ( !$hijri ) {
 1069+ $hijri = self::tsToHijri( $ts );
 1070+ }
 1071+ $num = $hijri[0];
 1072+ break;
 1073+ case 'xjY':
 1074+ if ( !$hebrew ) {
 1075+ $hebrew = self::tsToHebrew( $ts );
 1076+ }
 1077+ $num = $hebrew[0];
 1078+ break;
 1079+ case 'xkY':
 1080+ if ( !$thai ) {
 1081+ $thai = self::tsToYear( $ts, 'thai' );
 1082+ }
 1083+ $num = $thai[0];
 1084+ break;
 1085+ case 'xoY':
 1086+ if ( !$minguo ) {
 1087+ $minguo = self::tsToYear( $ts, 'minguo' );
 1088+ }
 1089+ $num = $minguo[0];
 1090+ break;
 1091+ case 'xtY':
 1092+ if ( !$tenno ) {
 1093+ $tenno = self::tsToYear( $ts, 'tenno' );
 1094+ }
 1095+ $num = $tenno[0];
 1096+ break;
 1097+ case 'y':
 1098+ $num = substr( $ts, 2, 2 );
 1099+ break;
 1100+ case 'a':
 1101+ $s .= intval( substr( $ts, 8, 2 ) ) < 12 ? 'am' : 'pm';
 1102+ break;
 1103+ case 'A':
 1104+ $s .= intval( substr( $ts, 8, 2 ) ) < 12 ? 'AM' : 'PM';
 1105+ break;
 1106+ case 'g':
 1107+ $h = substr( $ts, 8, 2 );
 1108+ $num = $h % 12 ? $h % 12 : 12;
 1109+ break;
 1110+ case 'G':
 1111+ $num = intval( substr( $ts, 8, 2 ) );
 1112+ break;
 1113+ case 'h':
 1114+ $h = substr( $ts, 8, 2 );
 1115+ $num = sprintf( '%02d', $h % 12 ? $h % 12 : 12 );
 1116+ break;
 1117+ case 'H':
 1118+ $num = substr( $ts, 8, 2 );
 1119+ break;
 1120+ case 'i':
 1121+ $num = substr( $ts, 10, 2 );
 1122+ break;
 1123+ case 's':
 1124+ $num = substr( $ts, 12, 2 );
 1125+ break;
 1126+ case 'c':
 1127+ if ( !$unix ) {
 1128+ $unix = wfTimestamp( TS_UNIX, $ts );
 1129+ }
 1130+ $s .= gmdate( 'c', $unix );
 1131+ break;
 1132+ case 'r':
 1133+ if ( !$unix ) {
 1134+ $unix = wfTimestamp( TS_UNIX, $ts );
 1135+ }
 1136+ $s .= gmdate( 'r', $unix );
 1137+ break;
 1138+ case 'U':
 1139+ if ( !$unix ) {
 1140+ $unix = wfTimestamp( TS_UNIX, $ts );
 1141+ }
 1142+ $num = $unix;
 1143+ break;
 1144+ case '\\':
 1145+ # Backslash escaping
 1146+ if ( $p < strlen( $format ) - 1 ) {
 1147+ $s .= $format[++$p];
 1148+ } else {
 1149+ $s .= '\\';
 1150+ }
 1151+ break;
 1152+ case '"':
 1153+ # Quoted literal
 1154+ if ( $p < strlen( $format ) - 1 ) {
 1155+ $endQuote = strpos( $format, '"', $p + 1 );
 1156+ if ( $endQuote === false ) {
 1157+ # No terminating quote, assume literal "
 1158+ $s .= '"';
 1159+ } else {
 1160+ $s .= substr( $format, $p + 1, $endQuote - $p - 1 );
 1161+ $p = $endQuote;
 1162+ }
 1163+ } else {
 1164+ # Quote at end of string, assume literal "
 1165+ $s .= '"';
 1166+ }
 1167+ break;
 1168+ default:
 1169+ $s .= $format[$p];
 1170+ }
 1171+ if ( $num !== false ) {
 1172+ if ( $rawToggle || $raw ) {
 1173+ $s .= $num;
 1174+ $raw = false;
 1175+ } elseif ( $roman ) {
 1176+ $s .= self::romanNumeral( $num );
 1177+ $roman = false;
 1178+ } elseif ( $hebrewNum ) {
 1179+ $s .= self::hebrewNumeral( $num );
 1180+ $hebrewNum = false;
 1181+ } else {
 1182+ $s .= $this->formatNum( $num, true );
 1183+ }
 1184+ }
 1185+ }
 1186+ return $s;
 1187+ }
 1188+
 1189+ private static $GREG_DAYS = array( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
 1190+ private static $IRANIAN_DAYS = array( 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 );
 1191+
 1192+ /**
 1193+ * Algorithm by Roozbeh Pournader and Mohammad Toossi to convert
 1194+ * Gregorian dates to Iranian dates. Originally written in C, it
 1195+ * is released under the terms of GNU Lesser General Public
 1196+ * License. Conversion to PHP was performed by Niklas Laxström.
 1197+ *
 1198+ * Link: http://www.farsiweb.info/jalali/jalali.c
 1199+ *
 1200+ * @param $ts string
 1201+ *
 1202+ * @return string
 1203+ */
 1204+ private static function tsToIranian( $ts ) {
 1205+ $gy = substr( $ts, 0, 4 ) -1600;
 1206+ $gm = substr( $ts, 4, 2 ) -1;
 1207+ $gd = substr( $ts, 6, 2 ) -1;
 1208+
 1209+ # Days passed from the beginning (including leap years)
 1210+ $gDayNo = 365 * $gy
 1211+ + floor( ( $gy + 3 ) / 4 )
 1212+ - floor( ( $gy + 99 ) / 100 )
 1213+ + floor( ( $gy + 399 ) / 400 );
 1214+
 1215+
 1216+ // Add days of the past months of this year
 1217+ for ( $i = 0; $i < $gm; $i++ ) {
 1218+ $gDayNo += self::$GREG_DAYS[$i];
 1219+ }
 1220+
 1221+ // Leap years
 1222+ if ( $gm > 1 && ( ( $gy % 4 === 0 && $gy % 100 !== 0 || ( $gy % 400 == 0 ) ) ) ) {
 1223+ $gDayNo++;
 1224+ }
 1225+
 1226+ // Days passed in current month
 1227+ $gDayNo += $gd;
 1228+
 1229+ $jDayNo = $gDayNo - 79;
 1230+
 1231+ $jNp = floor( $jDayNo / 12053 );
 1232+ $jDayNo %= 12053;
 1233+
 1234+ $jy = 979 + 33 * $jNp + 4 * floor( $jDayNo / 1461 );
 1235+ $jDayNo %= 1461;
 1236+
 1237+ if ( $jDayNo >= 366 ) {
 1238+ $jy += floor( ( $jDayNo - 1 ) / 365 );
 1239+ $jDayNo = floor( ( $jDayNo - 1 ) % 365 );
 1240+ }
 1241+
 1242+ for ( $i = 0; $i < 11 && $jDayNo >= self::$IRANIAN_DAYS[$i]; $i++ ) {
 1243+ $jDayNo -= self::$IRANIAN_DAYS[$i];
 1244+ }
 1245+
 1246+ $jm = $i + 1;
 1247+ $jd = $jDayNo + 1;
 1248+
 1249+ return array( $jy, $jm, $jd );
 1250+ }
 1251+
 1252+ /**
 1253+ * Converting Gregorian dates to Hijri dates.
 1254+ *
 1255+ * Based on a PHP-Nuke block by Sharjeel which is released under GNU/GPL license
 1256+ *
 1257+ * @link http://phpnuke.org/modules.php?name=News&file=article&sid=8234&mode=thread&order=0&thold=0
 1258+ *
 1259+ * @param $ts string
 1260+ *
 1261+ * @return string
 1262+ */
 1263+ private static function tsToHijri( $ts ) {
 1264+ $year = substr( $ts, 0, 4 );
 1265+ $month = substr( $ts, 4, 2 );
 1266+ $day = substr( $ts, 6, 2 );
 1267+
 1268+ $zyr = $year;
 1269+ $zd = $day;
 1270+ $zm = $month;
 1271+ $zy = $zyr;
 1272+
 1273+ if (
 1274+ ( $zy > 1582 ) || ( ( $zy == 1582 ) && ( $zm > 10 ) ) ||
 1275+ ( ( $zy == 1582 ) && ( $zm == 10 ) && ( $zd > 14 ) )
 1276+ )
 1277+ {
 1278+ $zjd = (int)( ( 1461 * ( $zy + 4800 + (int)( ( $zm - 14 ) / 12 ) ) ) / 4 ) +
 1279+ (int)( ( 367 * ( $zm - 2 - 12 * ( (int)( ( $zm - 14 ) / 12 ) ) ) ) / 12 ) -
 1280+ (int)( ( 3 * (int)( ( ( $zy + 4900 + (int)( ( $zm - 14 ) / 12 ) ) / 100 ) ) ) / 4 ) +
 1281+ $zd - 32075;
 1282+ } else {
 1283+ $zjd = 367 * $zy - (int)( ( 7 * ( $zy + 5001 + (int)( ( $zm - 9 ) / 7 ) ) ) / 4 ) +
 1284+ (int)( ( 275 * $zm ) / 9 ) + $zd + 1729777;
 1285+ }
 1286+
 1287+ $zl = $zjd -1948440 + 10632;
 1288+ $zn = (int)( ( $zl - 1 ) / 10631 );
 1289+ $zl = $zl - 10631 * $zn + 354;
 1290+ $zj = ( (int)( ( 10985 - $zl ) / 5316 ) ) * ( (int)( ( 50 * $zl ) / 17719 ) ) + ( (int)( $zl / 5670 ) ) * ( (int)( ( 43 * $zl ) / 15238 ) );
 1291+ $zl = $zl - ( (int)( ( 30 - $zj ) / 15 ) ) * ( (int)( ( 17719 * $zj ) / 50 ) ) - ( (int)( $zj / 16 ) ) * ( (int)( ( 15238 * $zj ) / 43 ) ) + 29;
 1292+ $zm = (int)( ( 24 * $zl ) / 709 );
 1293+ $zd = $zl - (int)( ( 709 * $zm ) / 24 );
 1294+ $zy = 30 * $zn + $zj - 30;
 1295+
 1296+ return array( $zy, $zm, $zd );
 1297+ }
 1298+
 1299+ /**
 1300+ * Converting Gregorian dates to Hebrew dates.
 1301+ *
 1302+ * Based on a JavaScript code by Abu Mami and Yisrael Hersch
 1303+ * (abu-mami@kaluach.net, http://www.kaluach.net), who permitted
 1304+ * to translate the relevant functions into PHP and release them under
 1305+ * GNU GPL.
 1306+ *
 1307+ * The months are counted from Tishrei = 1. In a leap year, Adar I is 13
 1308+ * and Adar II is 14. In a non-leap year, Adar is 6.
 1309+ *
 1310+ * @param $ts string
 1311+ *
 1312+ * @return string
 1313+ */
 1314+ private static function tsToHebrew( $ts ) {
 1315+ # Parse date
 1316+ $year = substr( $ts, 0, 4 );
 1317+ $month = substr( $ts, 4, 2 );
 1318+ $day = substr( $ts, 6, 2 );
 1319+
 1320+ # Calculate Hebrew year
 1321+ $hebrewYear = $year + 3760;
 1322+
 1323+ # Month number when September = 1, August = 12
 1324+ $month += 4;
 1325+ if ( $month > 12 ) {
 1326+ # Next year
 1327+ $month -= 12;
 1328+ $year++;
 1329+ $hebrewYear++;
 1330+ }
 1331+
 1332+ # Calculate day of year from 1 September
 1333+ $dayOfYear = $day;
 1334+ for ( $i = 1; $i < $month; $i++ ) {
 1335+ if ( $i == 6 ) {
 1336+ # February
 1337+ $dayOfYear += 28;
 1338+ # Check if the year is leap
 1339+ if ( $year % 400 == 0 || ( $year % 4 == 0 && $year % 100 > 0 ) ) {
 1340+ $dayOfYear++;
 1341+ }
 1342+ } elseif ( $i == 8 || $i == 10 || $i == 1 || $i == 3 ) {
 1343+ $dayOfYear += 30;
 1344+ } else {
 1345+ $dayOfYear += 31;
 1346+ }
 1347+ }
 1348+
 1349+ # Calculate the start of the Hebrew year
 1350+ $start = self::hebrewYearStart( $hebrewYear );
 1351+
 1352+ # Calculate next year's start
 1353+ if ( $dayOfYear <= $start ) {
 1354+ # Day is before the start of the year - it is the previous year
 1355+ # Next year's start
 1356+ $nextStart = $start;
 1357+ # Previous year
 1358+ $year--;
 1359+ $hebrewYear--;
 1360+ # Add days since previous year's 1 September
 1361+ $dayOfYear += 365;
 1362+ if ( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
 1363+ # Leap year
 1364+ $dayOfYear++;
 1365+ }
 1366+ # Start of the new (previous) year
 1367+ $start = self::hebrewYearStart( $hebrewYear );
 1368+ } else {
 1369+ # Next year's start
 1370+ $nextStart = self::hebrewYearStart( $hebrewYear + 1 );
 1371+ }
 1372+
 1373+ # Calculate Hebrew day of year
 1374+ $hebrewDayOfYear = $dayOfYear - $start;
 1375+
 1376+ # Difference between year's days
 1377+ $diff = $nextStart - $start;
 1378+ # Add 12 (or 13 for leap years) days to ignore the difference between
 1379+ # Hebrew and Gregorian year (353 at least vs. 365/6) - now the
 1380+ # difference is only about the year type
 1381+ if ( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
 1382+ $diff += 13;
 1383+ } else {
 1384+ $diff += 12;
 1385+ }
 1386+
 1387+ # Check the year pattern, and is leap year
 1388+ # 0 means an incomplete year, 1 means a regular year, 2 means a complete year
 1389+ # This is mod 30, to work on both leap years (which add 30 days of Adar I)
 1390+ # and non-leap years
 1391+ $yearPattern = $diff % 30;
 1392+ # Check if leap year
 1393+ $isLeap = $diff >= 30;
 1394+
 1395+ # Calculate day in the month from number of day in the Hebrew year
 1396+ # Don't check Adar - if the day is not in Adar, we will stop before;
 1397+ # if it is in Adar, we will use it to check if it is Adar I or Adar II
 1398+ $hebrewDay = $hebrewDayOfYear;
 1399+ $hebrewMonth = 1;
 1400+ $days = 0;
 1401+ while ( $hebrewMonth <= 12 ) {
 1402+ # Calculate days in this month
 1403+ if ( $isLeap && $hebrewMonth == 6 ) {
 1404+ # Adar in a leap year
 1405+ if ( $isLeap ) {
 1406+ # Leap year - has Adar I, with 30 days, and Adar II, with 29 days
 1407+ $days = 30;
 1408+ if ( $hebrewDay <= $days ) {
 1409+ # Day in Adar I
 1410+ $hebrewMonth = 13;
 1411+ } else {
 1412+ # Subtract the days of Adar I
 1413+ $hebrewDay -= $days;
 1414+ # Try Adar II
 1415+ $days = 29;
 1416+ if ( $hebrewDay <= $days ) {
 1417+ # Day in Adar II
 1418+ $hebrewMonth = 14;
 1419+ }
 1420+ }
 1421+ }
 1422+ } elseif ( $hebrewMonth == 2 && $yearPattern == 2 ) {
 1423+ # Cheshvan in a complete year (otherwise as the rule below)
 1424+ $days = 30;
 1425+ } elseif ( $hebrewMonth == 3 && $yearPattern == 0 ) {
 1426+ # Kislev in an incomplete year (otherwise as the rule below)
 1427+ $days = 29;
 1428+ } else {
 1429+ # Odd months have 30 days, even have 29
 1430+ $days = 30 - ( $hebrewMonth - 1 ) % 2;
 1431+ }
 1432+ if ( $hebrewDay <= $days ) {
 1433+ # In the current month
 1434+ break;
 1435+ } else {
 1436+ # Subtract the days of the current month
 1437+ $hebrewDay -= $days;
 1438+ # Try in the next month
 1439+ $hebrewMonth++;
 1440+ }
 1441+ }
 1442+
 1443+ return array( $hebrewYear, $hebrewMonth, $hebrewDay, $days );
 1444+ }
 1445+
 1446+ /**
 1447+ * This calculates the Hebrew year start, as days since 1 September.
 1448+ * Based on Carl Friedrich Gauss algorithm for finding Easter date.
 1449+ * Used for Hebrew date.
 1450+ *
 1451+ * @param $year int
 1452+ *
 1453+ * @return string
 1454+ */
 1455+ private static function hebrewYearStart( $year ) {
 1456+ $a = intval( ( 12 * ( $year - 1 ) + 17 ) % 19 );
 1457+ $b = intval( ( $year - 1 ) % 4 );
 1458+ $m = 32.044093161144 + 1.5542417966212 * $a + $b / 4.0 - 0.0031777940220923 * ( $year - 1 );
 1459+ if ( $m < 0 ) {
 1460+ $m--;
 1461+ }
 1462+ $Mar = intval( $m );
 1463+ if ( $m < 0 ) {
 1464+ $m++;
 1465+ }
 1466+ $m -= $Mar;
 1467+
 1468+ $c = intval( ( $Mar + 3 * ( $year - 1 ) + 5 * $b + 5 ) % 7 );
 1469+ if ( $c == 0 && $a > 11 && $m >= 0.89772376543210 ) {
 1470+ $Mar++;
 1471+ } elseif ( $c == 1 && $a > 6 && $m >= 0.63287037037037 ) {
 1472+ $Mar += 2;
 1473+ } elseif ( $c == 2 || $c == 4 || $c == 6 ) {
 1474+ $Mar++;
 1475+ }
 1476+
 1477+ $Mar += intval( ( $year - 3761 ) / 100 ) - intval( ( $year - 3761 ) / 400 ) - 24;
 1478+ return $Mar;
 1479+ }
 1480+
 1481+ /**
 1482+ * Algorithm to convert Gregorian dates to Thai solar dates,
 1483+ * Minguo dates or Minguo dates.
 1484+ *
 1485+ * Link: http://en.wikipedia.org/wiki/Thai_solar_calendar
 1486+ * http://en.wikipedia.org/wiki/Minguo_calendar
 1487+ * http://en.wikipedia.org/wiki/Japanese_era_name
 1488+ *
 1489+ * @param $ts String: 14-character timestamp
 1490+ * @param $cName String: calender name
 1491+ * @return Array: converted year, month, day
 1492+ */
 1493+ private static function tsToYear( $ts, $cName ) {
 1494+ $gy = substr( $ts, 0, 4 );
 1495+ $gm = substr( $ts, 4, 2 );
 1496+ $gd = substr( $ts, 6, 2 );
 1497+
 1498+ if ( !strcmp( $cName, 'thai' ) ) {
 1499+ # Thai solar dates
 1500+ # Add 543 years to the Gregorian calendar
 1501+ # Months and days are identical
 1502+ $gy_offset = $gy + 543;
 1503+ } elseif ( ( !strcmp( $cName, 'minguo' ) ) || !strcmp( $cName, 'juche' ) ) {
 1504+ # Minguo dates
 1505+ # Deduct 1911 years from the Gregorian calendar
 1506+ # Months and days are identical
 1507+ $gy_offset = $gy - 1911;
 1508+ } elseif ( !strcmp( $cName, 'tenno' ) ) {
 1509+ # NengÅ� dates up to Meiji period
 1510+ # Deduct years from the Gregorian calendar
 1511+ # depending on the nengo periods
 1512+ # Months and days are identical
 1513+ if ( ( $gy < 1912 ) || ( ( $gy == 1912 ) && ( $gm < 7 ) ) || ( ( $gy == 1912 ) && ( $gm == 7 ) && ( $gd < 31 ) ) ) {
 1514+ # Meiji period
 1515+ $gy_gannen = $gy - 1868 + 1;
 1516+ $gy_offset = $gy_gannen;
 1517+ if ( $gy_gannen == 1 ) {
 1518+ $gy_offset = 'å…ƒ';
 1519+ }
 1520+ $gy_offset = '明治' . $gy_offset;
 1521+ } elseif (
 1522+ ( ( $gy == 1912 ) && ( $gm == 7 ) && ( $gd == 31 ) ) ||
 1523+ ( ( $gy == 1912 ) && ( $gm >= 8 ) ) ||
 1524+ ( ( $gy > 1912 ) && ( $gy < 1926 ) ) ||
 1525+ ( ( $gy == 1926 ) && ( $gm < 12 ) ) ||
 1526+ ( ( $gy == 1926 ) && ( $gm == 12 ) && ( $gd < 26 ) )
 1527+ )
 1528+ {
 1529+ # TaishÅ� period
 1530+ $gy_gannen = $gy - 1912 + 1;
 1531+ $gy_offset = $gy_gannen;
 1532+ if ( $gy_gannen == 1 ) {
 1533+ $gy_offset = 'å…ƒ';
 1534+ }
 1535+ $gy_offset = '大正' . $gy_offset;
 1536+ } elseif (
 1537+ ( ( $gy == 1926 ) && ( $gm == 12 ) && ( $gd >= 26 ) ) ||
 1538+ ( ( $gy > 1926 ) && ( $gy < 1989 ) ) ||
 1539+ ( ( $gy == 1989 ) && ( $gm == 1 ) && ( $gd < 8 ) )
 1540+ )
 1541+ {
 1542+ # ShÅ�wa period
 1543+ $gy_gannen = $gy - 1926 + 1;
 1544+ $gy_offset = $gy_gannen;
 1545+ if ( $gy_gannen == 1 ) {
 1546+ $gy_offset = 'å…ƒ';
 1547+ }
 1548+ $gy_offset = '昭和' . $gy_offset;
 1549+ } else {
 1550+ # Heisei period
 1551+ $gy_gannen = $gy - 1989 + 1;
 1552+ $gy_offset = $gy_gannen;
 1553+ if ( $gy_gannen == 1 ) {
 1554+ $gy_offset = 'å…ƒ';
 1555+ }
 1556+ $gy_offset = 'å¹³æˆ�' . $gy_offset;
 1557+ }
 1558+ } else {
 1559+ $gy_offset = $gy;
 1560+ }
 1561+
 1562+ return array( $gy_offset, $gm, $gd );
 1563+ }
 1564+
 1565+ /**
 1566+ * Roman number formatting up to 3000
 1567+ *
 1568+ * @param $num int
 1569+ *
 1570+ * @return string
 1571+ */
 1572+ static function romanNumeral( $num ) {
 1573+ static $table = array(
 1574+ array( '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X' ),
 1575+ array( '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', 'C' ),
 1576+ array( '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', 'M' ),
 1577+ array( '', 'M', 'MM', 'MMM' )
 1578+ );
 1579+
 1580+ $num = intval( $num );
 1581+ if ( $num > 3000 || $num <= 0 ) {
 1582+ return $num;
 1583+ }
 1584+
 1585+ $s = '';
 1586+ for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
 1587+ if ( $num >= $pow10 ) {
 1588+ $s .= $table[$i][floor( $num / $pow10 )];
 1589+ }
 1590+ $num = $num % $pow10;
 1591+ }
 1592+ return $s;
 1593+ }
 1594+
 1595+ /**
 1596+ * Hebrew Gematria number formatting up to 9999
 1597+ *
 1598+ * @param $num int
 1599+ *
 1600+ * @return string
 1601+ */
 1602+ static function hebrewNumeral( $num ) {
 1603+ static $table = array(
 1604+ array( '', '×�', 'ב', '×’', 'ד', '×”', 'ו', '×–', '×—', 'ט', '×™' ),
 1605+ array( '', '×™', '×›', 'ל', 'מ', '× ', 'ס', '×¢', 'פ', 'צ', 'ק' ),
 1606+ array( '', 'ק', 'ר', 'ש', 'ת', 'תק', 'תר', 'תש', 'תת', 'תתק', 'תתר' ),
 1607+ array( '', '×�', 'ב', '×’', 'ד', '×”', 'ו', '×–', '×—', 'ט', '×™' )
 1608+ );
 1609+
 1610+ $num = intval( $num );
 1611+ if ( $num > 9999 || $num <= 0 ) {
 1612+ return $num;
 1613+ }
 1614+
 1615+ $s = '';
 1616+ for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
 1617+ if ( $num >= $pow10 ) {
 1618+ if ( $num == 15 || $num == 16 ) {
 1619+ $s .= $table[0][9] . $table[0][$num - 9];
 1620+ $num = 0;
 1621+ } else {
 1622+ $s .= $table[$i][intval( ( $num / $pow10 ) )];
 1623+ if ( $pow10 == 1000 ) {
 1624+ $s .= "'";
 1625+ }
 1626+ }
 1627+ }
 1628+ $num = $num % $pow10;
 1629+ }
 1630+ if ( strlen( $s ) == 2 ) {
 1631+ $str = $s . "'";
 1632+ } else {
 1633+ $str = substr( $s, 0, strlen( $s ) - 2 ) . '"';
 1634+ $str .= substr( $s, strlen( $s ) - 2, 2 );
 1635+ }
 1636+ $start = substr( $str, 0, strlen( $str ) - 2 );
 1637+ $end = substr( $str, strlen( $str ) - 2 );
 1638+ switch( $end ) {
 1639+ case '×›':
 1640+ $str = $start . 'ך';
 1641+ break;
 1642+ case 'מ':
 1643+ $str = $start . '×�';
 1644+ break;
 1645+ case '× ':
 1646+ $str = $start . 'ן';
 1647+ break;
 1648+ case 'פ':
 1649+ $str = $start . '×£';
 1650+ break;
 1651+ case 'צ':
 1652+ $str = $start . '×¥';
 1653+ break;
 1654+ }
 1655+ return $str;
 1656+ }
 1657+
 1658+ /**
 1659+ * This is meant to be used by time(), date(), and timeanddate() to get
 1660+ * the date preference they're supposed to use, it should be used in
 1661+ * all children.
 1662+ *
 1663+ *<code>
 1664+ * function timeanddate([...], $format = true) {
 1665+ * $datePreference = $this->dateFormat($format);
 1666+ * [...]
 1667+ * }
 1668+ *</code>
 1669+ *
 1670+ * @param $usePrefs Mixed: if true, the user's preference is used
 1671+ * if false, the site/language default is used
 1672+ * if int/string, assumed to be a format.
 1673+ * @return string
 1674+ */
 1675+ function dateFormat( $usePrefs = true ) {
 1676+ global $wgUser;
 1677+
 1678+ if ( is_bool( $usePrefs ) ) {
 1679+ if ( $usePrefs ) {
 1680+ $datePreference = $wgUser->getDatePreference();
 1681+ } else {
 1682+ $datePreference = (string)User::getDefaultOption( 'date' );
 1683+ }
 1684+ } else {
 1685+ $datePreference = (string)$usePrefs;
 1686+ }
 1687+
 1688+ // return int
 1689+ if ( $datePreference == '' ) {
 1690+ return 'default';
 1691+ }
 1692+
 1693+ return $datePreference;
 1694+ }
 1695+
 1696+ /**
 1697+ * Get a format string for a given type and preference
 1698+ * @param $type string May be date, time or both
 1699+ * @param $pref string The format name as it appears in Messages*.php
 1700+ *
 1701+ * @return string
 1702+ */
 1703+ function getDateFormatString( $type, $pref ) {
 1704+ if ( !isset( $this->dateFormatStrings[$type][$pref] ) ) {
 1705+ if ( $pref == 'default' ) {
 1706+ $pref = $this->getDefaultDateFormat();
 1707+ $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
 1708+ } else {
 1709+ $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
 1710+ if ( is_null( $df ) ) {
 1711+ $pref = $this->getDefaultDateFormat();
 1712+ $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
 1713+ }
 1714+ }
 1715+ $this->dateFormatStrings[$type][$pref] = $df;
 1716+ }
 1717+ return $this->dateFormatStrings[$type][$pref];
 1718+ }
 1719+
 1720+ /**
 1721+ * @param $ts Mixed: the time format which needs to be turned into a
 1722+ * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
 1723+ * @param $adj Bool: whether to adjust the time output according to the
 1724+ * user configured offset ($timecorrection)
 1725+ * @param $format Mixed: true to use user's date format preference
 1726+ * @param $timecorrection String|bool the time offset as returned by
 1727+ * validateTimeZone() in Special:Preferences
 1728+ * @return string
 1729+ */
 1730+ function date( $ts, $adj = false, $format = true, $timecorrection = false ) {
 1731+ $ts = wfTimestamp( TS_MW, $ts );
 1732+ if ( $adj ) {
 1733+ $ts = $this->userAdjust( $ts, $timecorrection );
 1734+ }
 1735+ $df = $this->getDateFormatString( 'date', $this->dateFormat( $format ) );
 1736+ return $this->sprintfDate( $df, $ts );
 1737+ }
 1738+
 1739+ /**
 1740+ * @param $ts Mixed: the time format which needs to be turned into a
 1741+ * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
 1742+ * @param $adj Bool: whether to adjust the time output according to the
 1743+ * user configured offset ($timecorrection)
 1744+ * @param $format Mixed: true to use user's date format preference
 1745+ * @param $timecorrection String|bool the time offset as returned by
 1746+ * validateTimeZone() in Special:Preferences
 1747+ * @return string
 1748+ */
 1749+ function time( $ts, $adj = false, $format = true, $timecorrection = false ) {
 1750+ $ts = wfTimestamp( TS_MW, $ts );
 1751+ if ( $adj ) {
 1752+ $ts = $this->userAdjust( $ts, $timecorrection );
 1753+ }
 1754+ $df = $this->getDateFormatString( 'time', $this->dateFormat( $format ) );
 1755+ return $this->sprintfDate( $df, $ts );
 1756+ }
 1757+
 1758+ /**
 1759+ * @param $ts Mixed: the time format which needs to be turned into a
 1760+ * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
 1761+ * @param $adj Bool: whether to adjust the time output according to the
 1762+ * user configured offset ($timecorrection)
 1763+ * @param $format Mixed: what format to return, if it's false output the
 1764+ * default one (default true)
 1765+ * @param $timecorrection String|bool the time offset as returned by
 1766+ * validateTimeZone() in Special:Preferences
 1767+ * @return string
 1768+ */
 1769+ function timeanddate( $ts, $adj = false, $format = true, $timecorrection = false ) {
 1770+ $ts = wfTimestamp( TS_MW, $ts );
 1771+ if ( $adj ) {
 1772+ $ts = $this->userAdjust( $ts, $timecorrection );
 1773+ }
 1774+ $df = $this->getDateFormatString( 'both', $this->dateFormat( $format ) );
 1775+ return $this->sprintfDate( $df, $ts );
 1776+ }
 1777+
 1778+ /**
 1779+ * @param $key string
 1780+ * @return array|null
 1781+ */
 1782+ function getMessage( $key ) {
 1783+ return self::$dataCache->getSubitem( $this->mCode, 'messages', $key );
 1784+ }
 1785+
 1786+ /**
 1787+ * @return array
 1788+ */
 1789+ function getAllMessages() {
 1790+ return self::$dataCache->getItem( $this->mCode, 'messages' );
 1791+ }
 1792+
 1793+ /**
 1794+ * @param $in
 1795+ * @param $out
 1796+ * @param $string
 1797+ * @return string
 1798+ */
 1799+ function iconv( $in, $out, $string ) {
 1800+ # This is a wrapper for iconv in all languages except esperanto,
 1801+ # which does some nasty x-conversions beforehand
 1802+
 1803+ # Even with //IGNORE iconv can whine about illegal characters in
 1804+ # *input* string. We just ignore those too.
 1805+ # REF: http://bugs.php.net/bug.php?id=37166
 1806+ # REF: https://bugzilla.wikimedia.org/show_bug.cgi?id=16885
 1807+ wfSuppressWarnings();
 1808+ $text = iconv( $in, $out . '//IGNORE', $string );
 1809+ wfRestoreWarnings();
 1810+ return $text;
 1811+ }
 1812+
 1813+ // callback functions for uc(), lc(), ucwords(), ucwordbreaks()
 1814+
 1815+ /**
 1816+ * @param $matches array
 1817+ * @return mixed|string
 1818+ */
 1819+ function ucwordbreaksCallbackAscii( $matches ) {
 1820+ return $this->ucfirst( $matches[1] );
 1821+ }
 1822+
 1823+ /**
 1824+ * @param $matches array
 1825+ * @return string
 1826+ */
 1827+ function ucwordbreaksCallbackMB( $matches ) {
 1828+ return mb_strtoupper( $matches[0] );
 1829+ }
 1830+
 1831+ /**
 1832+ * @param $matches array
 1833+ * @return string
 1834+ */
 1835+ function ucCallback( $matches ) {
 1836+ list( $wikiUpperChars ) = self::getCaseMaps();
 1837+ return strtr( $matches[1], $wikiUpperChars );
 1838+ }
 1839+
 1840+ /**
 1841+ * @param $matches array
 1842+ * @return string
 1843+ */
 1844+ function lcCallback( $matches ) {
 1845+ list( , $wikiLowerChars ) = self::getCaseMaps();
 1846+ return strtr( $matches[1], $wikiLowerChars );
 1847+ }
 1848+
 1849+ /**
 1850+ * @param $matches array
 1851+ * @return string
 1852+ */
 1853+ function ucwordsCallbackMB( $matches ) {
 1854+ return mb_strtoupper( $matches[0] );
 1855+ }
 1856+
 1857+ /**
 1858+ * @param $matches array
 1859+ * @return string
 1860+ */
 1861+ function ucwordsCallbackWiki( $matches ) {
 1862+ list( $wikiUpperChars ) = self::getCaseMaps();
 1863+ return strtr( $matches[0], $wikiUpperChars );
 1864+ }
 1865+
 1866+ /**
 1867+ * Make a string's first character uppercase
 1868+ *
 1869+ * @param $str string
 1870+ *
 1871+ * @return string
 1872+ */
 1873+ function ucfirst( $str ) {
 1874+ $o = ord( $str );
 1875+ if ( $o < 96 ) { // if already uppercase...
 1876+ return $str;
 1877+ } elseif ( $o < 128 ) {
 1878+ return ucfirst( $str ); // use PHP's ucfirst()
 1879+ } else {
 1880+ // fall back to more complex logic in case of multibyte strings
 1881+ return $this->uc( $str, true );
 1882+ }
 1883+ }
 1884+
 1885+ /**
 1886+ * Convert a string to uppercase
 1887+ *
 1888+ * @param $str string
 1889+ * @param $first bool
 1890+ *
 1891+ * @return string
 1892+ */
 1893+ function uc( $str, $first = false ) {
 1894+ if ( function_exists( 'mb_strtoupper' ) ) {
 1895+ if ( $first ) {
 1896+ if ( $this->isMultibyte( $str ) ) {
 1897+ return mb_strtoupper( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
 1898+ } else {
 1899+ return ucfirst( $str );
 1900+ }
 1901+ } else {
 1902+ return $this->isMultibyte( $str ) ? mb_strtoupper( $str ) : strtoupper( $str );
 1903+ }
 1904+ } else {
 1905+ if ( $this->isMultibyte( $str ) ) {
 1906+ $x = $first ? '^' : '';
 1907+ return preg_replace_callback(
 1908+ "/$x([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/",
 1909+ array( $this, 'ucCallback' ),
 1910+ $str
 1911+ );
 1912+ } else {
 1913+ return $first ? ucfirst( $str ) : strtoupper( $str );
 1914+ }
 1915+ }
 1916+ }
 1917+
 1918+ /**
 1919+ * @param $str string
 1920+ * @return mixed|string
 1921+ */
 1922+ function lcfirst( $str ) {
 1923+ $o = ord( $str );
 1924+ if ( !$o ) {
 1925+ return strval( $str );
 1926+ } elseif ( $o >= 128 ) {
 1927+ return $this->lc( $str, true );
 1928+ } elseif ( $o > 96 ) {
 1929+ return $str;
 1930+ } else {
 1931+ $str[0] = strtolower( $str[0] );
 1932+ return $str;
 1933+ }
 1934+ }
 1935+
 1936+ /**
 1937+ * @param $str string
 1938+ * @param $first bool
 1939+ * @return mixed|string
 1940+ */
 1941+ function lc( $str, $first = false ) {
 1942+ if ( function_exists( 'mb_strtolower' ) ) {
 1943+ if ( $first ) {
 1944+ if ( $this->isMultibyte( $str ) ) {
 1945+ return mb_strtolower( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
 1946+ } else {
 1947+ return strtolower( substr( $str, 0, 1 ) ) . substr( $str, 1 );
 1948+ }
 1949+ } else {
 1950+ return $this->isMultibyte( $str ) ? mb_strtolower( $str ) : strtolower( $str );
 1951+ }
 1952+ } else {
 1953+ if ( $this->isMultibyte( $str ) ) {
 1954+ $x = $first ? '^' : '';
 1955+ return preg_replace_callback(
 1956+ "/$x([A-Z]|[\\xc0-\\xff][\\x80-\\xbf]*)/",
 1957+ array( $this, 'lcCallback' ),
 1958+ $str
 1959+ );
 1960+ } else {
 1961+ return $first ? strtolower( substr( $str, 0, 1 ) ) . substr( $str, 1 ) : strtolower( $str );
 1962+ }
 1963+ }
 1964+ }
 1965+
 1966+ /**
 1967+ * @param $str string
 1968+ * @return bool
 1969+ */
 1970+ function isMultibyte( $str ) {
 1971+ return (bool)preg_match( '/[\x80-\xff]/', $str );
 1972+ }
 1973+
 1974+ /**
 1975+ * @param $str string
 1976+ * @return mixed|string
 1977+ */
 1978+ function ucwords( $str ) {
 1979+ if ( $this->isMultibyte( $str ) ) {
 1980+ $str = $this->lc( $str );
 1981+
 1982+ // regexp to find first letter in each word (i.e. after each space)
 1983+ $replaceRegexp = "/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)| ([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/";
 1984+
 1985+ // function to use to capitalize a single char
 1986+ if ( function_exists( 'mb_strtoupper' ) ) {
 1987+ return preg_replace_callback(
 1988+ $replaceRegexp,
 1989+ array( $this, 'ucwordsCallbackMB' ),
 1990+ $str
 1991+ );
 1992+ } else {
 1993+ return preg_replace_callback(
 1994+ $replaceRegexp,
 1995+ array( $this, 'ucwordsCallbackWiki' ),
 1996+ $str
 1997+ );
 1998+ }
 1999+ } else {
 2000+ return ucwords( strtolower( $str ) );
 2001+ }
 2002+ }
 2003+
 2004+ /**
 2005+ * capitalize words at word breaks
 2006+ *
 2007+ * @param $str string
 2008+ * @return mixed
 2009+ */
 2010+ function ucwordbreaks( $str ) {
 2011+ if ( $this->isMultibyte( $str ) ) {
 2012+ $str = $this->lc( $str );
 2013+
 2014+ // since \b doesn't work for UTF-8, we explicitely define word break chars
 2015+ $breaks = "[ \-\(\)\}\{\.,\?!]";
 2016+
 2017+ // find first letter after word break
 2018+ $replaceRegexp = "/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)|$breaks([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/";
 2019+
 2020+ if ( function_exists( 'mb_strtoupper' ) ) {
 2021+ return preg_replace_callback(
 2022+ $replaceRegexp,
 2023+ array( $this, 'ucwordbreaksCallbackMB' ),
 2024+ $str
 2025+ );
 2026+ } else {
 2027+ return preg_replace_callback(
 2028+ $replaceRegexp,
 2029+ array( $this, 'ucwordsCallbackWiki' ),
 2030+ $str
 2031+ );
 2032+ }
 2033+ } else {
 2034+ return preg_replace_callback(
 2035+ '/\b([\w\x80-\xff]+)\b/',
 2036+ array( $this, 'ucwordbreaksCallbackAscii' ),
 2037+ $str
 2038+ );
 2039+ }
 2040+ }
 2041+
 2042+ /**
 2043+ * Return a case-folded representation of $s
 2044+ *
 2045+ * This is a representation such that caseFold($s1)==caseFold($s2) if $s1
 2046+ * and $s2 are the same except for the case of their characters. It is not
 2047+ * necessary for the value returned to make sense when displayed.
 2048+ *
 2049+ * Do *not* perform any other normalisation in this function. If a caller
 2050+ * uses this function when it should be using a more general normalisation
 2051+ * function, then fix the caller.
 2052+ *
 2053+ * @param $s string
 2054+ *
 2055+ * @return string
 2056+ */
 2057+ function caseFold( $s ) {
 2058+ return $this->uc( $s );
 2059+ }
 2060+
 2061+ /**
 2062+ * @param $s string
 2063+ * @return string
 2064+ */
 2065+ function checkTitleEncoding( $s ) {
 2066+ if ( is_array( $s ) ) {
 2067+ wfDebugDieBacktrace( 'Given array to checkTitleEncoding.' );
 2068+ }
 2069+ # Check for non-UTF-8 URLs
 2070+ $ishigh = preg_match( '/[\x80-\xff]/', $s );
 2071+ if ( !$ishigh ) {
 2072+ return $s;
 2073+ }
 2074+
 2075+ $isutf8 = preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
 2076+ '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
 2077+ if ( $isutf8 ) {
 2078+ return $s;
 2079+ }
 2080+
 2081+ return $this->iconv( $this->fallback8bitEncoding(), 'utf-8', $s );
 2082+ }
 2083+
 2084+ /**
 2085+ * @return array
 2086+ */
 2087+ function fallback8bitEncoding() {
 2088+ return self::$dataCache->getItem( $this->mCode, 'fallback8bitEncoding' );
 2089+ }
 2090+
 2091+ /**
 2092+ * Most writing systems use whitespace to break up words.
 2093+ * Some languages such as Chinese don't conventionally do this,
 2094+ * which requires special handling when breaking up words for
 2095+ * searching etc.
 2096+ *
 2097+ * @return bool
 2098+ */
 2099+ function hasWordBreaks() {
 2100+ return true;
 2101+ }
 2102+
 2103+ /**
 2104+ * Some languages such as Chinese require word segmentation,
 2105+ * Specify such segmentation when overridden in derived class.
 2106+ *
 2107+ * @param $string String
 2108+ * @return String
 2109+ */
 2110+ function segmentByWord( $string ) {
 2111+ return $string;
 2112+ }
 2113+
 2114+ /**
 2115+ * Some languages have special punctuation need to be normalized.
 2116+ * Make such changes here.
 2117+ *
 2118+ * @param $string String
 2119+ * @return String
 2120+ */
 2121+ function normalizeForSearch( $string ) {
 2122+ return self::convertDoubleWidth( $string );
 2123+ }
 2124+
 2125+ /**
 2126+ * convert double-width roman characters to single-width.
 2127+ * range: ff00-ff5f ~= 0020-007f
 2128+ *
 2129+ * @param $string string
 2130+ *
 2131+ * @return string
 2132+ */
 2133+ protected static function convertDoubleWidth( $string ) {
 2134+ static $full = null;
 2135+ static $half = null;
 2136+
 2137+ if ( $full === null ) {
 2138+ $fullWidth = "ï¼�123456789ABCDEFGHIJKLMNOPQRSTUVWXYZï½�bcdefghijklï½�nï½�ï½�qrstuvwxyz";
 2139+ $halfWidth = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 2140+ $full = str_split( $fullWidth, 3 );
 2141+ $half = str_split( $halfWidth );
 2142+ }
 2143+
 2144+ $string = str_replace( $full, $half, $string );
 2145+ return $string;
 2146+ }
 2147+
 2148+ /**
 2149+ * @param $string string
 2150+ * @param $pattern string
 2151+ * @return string
 2152+ */
 2153+ protected static function insertSpace( $string, $pattern ) {
 2154+ $string = preg_replace( $pattern, " $1 ", $string );
 2155+ $string = preg_replace( '/ +/', ' ', $string );
 2156+ return $string;
 2157+ }
 2158+
 2159+ /**
 2160+ * @param $termsArray array
 2161+ * @return array
 2162+ */
 2163+ function convertForSearchResult( $termsArray ) {
 2164+ # some languages, e.g. Chinese, need to do a conversion
 2165+ # in order for search results to be displayed correctly
 2166+ return $termsArray;
 2167+ }
 2168+
 2169+ /**
 2170+ * Get the first character of a string.
 2171+ *
 2172+ * @param $s string
 2173+ * @return string
 2174+ */
 2175+ function firstChar( $s ) {
 2176+ $matches = array();
 2177+ preg_match(
 2178+ '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
 2179+ '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})/',
 2180+ $s,
 2181+ $matches
 2182+ );
 2183+
 2184+ if ( isset( $matches[1] ) ) {
 2185+ if ( strlen( $matches[1] ) != 3 ) {
 2186+ return $matches[1];
 2187+ }
 2188+
 2189+ // Break down Hangul syllables to grab the first jamo
 2190+ $code = utf8ToCodepoint( $matches[1] );
 2191+ if ( $code < 0xac00 || 0xd7a4 <= $code ) {
 2192+ return $matches[1];
 2193+ } elseif ( $code < 0xb098 ) {
 2194+ return "\xe3\x84\xb1";
 2195+ } elseif ( $code < 0xb2e4 ) {
 2196+ return "\xe3\x84\xb4";
 2197+ } elseif ( $code < 0xb77c ) {
 2198+ return "\xe3\x84\xb7";
 2199+ } elseif ( $code < 0xb9c8 ) {
 2200+ return "\xe3\x84\xb9";
 2201+ } elseif ( $code < 0xbc14 ) {
 2202+ return "\xe3\x85\x81";
 2203+ } elseif ( $code < 0xc0ac ) {
 2204+ return "\xe3\x85\x82";
 2205+ } elseif ( $code < 0xc544 ) {
 2206+ return "\xe3\x85\x85";
 2207+ } elseif ( $code < 0xc790 ) {
 2208+ return "\xe3\x85\x87";
 2209+ } elseif ( $code < 0xcc28 ) {
 2210+ return "\xe3\x85\x88";
 2211+ } elseif ( $code < 0xce74 ) {
 2212+ return "\xe3\x85\x8a";
 2213+ } elseif ( $code < 0xd0c0 ) {
 2214+ return "\xe3\x85\x8b";
 2215+ } elseif ( $code < 0xd30c ) {
 2216+ return "\xe3\x85\x8c";
 2217+ } elseif ( $code < 0xd558 ) {
 2218+ return "\xe3\x85\x8d";
 2219+ } else {
 2220+ return "\xe3\x85\x8e";
 2221+ }
 2222+ } else {
 2223+ return '';
 2224+ }
 2225+ }
 2226+
 2227+ function initEncoding() {
 2228+ # Some languages may have an alternate char encoding option
 2229+ # (Esperanto X-coding, Japanese furigana conversion, etc)
 2230+ # If this language is used as the primary content language,
 2231+ # an override to the defaults can be set here on startup.
 2232+ }
 2233+
 2234+ /**
 2235+ * @param $s string
 2236+ * @return string
 2237+ */
 2238+ function recodeForEdit( $s ) {
 2239+ # For some languages we'll want to explicitly specify
 2240+ # which characters make it into the edit box raw
 2241+ # or are converted in some way or another.
 2242+ global $wgEditEncoding;
 2243+ if ( $wgEditEncoding == '' || $wgEditEncoding == 'UTF-8' ) {
 2244+ return $s;
 2245+ } else {
 2246+ return $this->iconv( 'UTF-8', $wgEditEncoding, $s );
 2247+ }
 2248+ }
 2249+
 2250+ /**
 2251+ * @param $s string
 2252+ * @return string
 2253+ */
 2254+ function recodeInput( $s ) {
 2255+ # Take the previous into account.
 2256+ global $wgEditEncoding;
 2257+ if ( $wgEditEncoding != '' ) {
 2258+ $enc = $wgEditEncoding;
 2259+ } else {
 2260+ $enc = 'UTF-8';
 2261+ }
 2262+ if ( $enc == 'UTF-8' ) {
 2263+ return $s;
 2264+ } else {
 2265+ return $this->iconv( $enc, 'UTF-8', $s );
 2266+ }
 2267+ }
 2268+
 2269+ /**
 2270+ * Convert a UTF-8 string to normal form C. In Malayalam and Arabic, this
 2271+ * also cleans up certain backwards-compatible sequences, converting them
 2272+ * to the modern Unicode equivalent.
 2273+ *
 2274+ * This is language-specific for performance reasons only.
 2275+ *
 2276+ * @param $s string
 2277+ *
 2278+ * @return string
 2279+ */
 2280+ function normalize( $s ) {
 2281+ global $wgAllUnicodeFixes;
 2282+ $s = UtfNormal::cleanUp( $s );
 2283+ if ( $wgAllUnicodeFixes ) {
 2284+ $s = $this->transformUsingPairFile( 'normalize-ar.ser', $s );
 2285+ $s = $this->transformUsingPairFile( 'normalize-ml.ser', $s );
 2286+ }
 2287+
 2288+ return $s;
 2289+ }
 2290+
 2291+ /**
 2292+ * Transform a string using serialized data stored in the given file (which
 2293+ * must be in the serialized subdirectory of $IP). The file contains pairs
 2294+ * mapping source characters to destination characters.
 2295+ *
 2296+ * The data is cached in process memory. This will go faster if you have the
 2297+ * FastStringSearch extension.
 2298+ *
 2299+ * @param $file string
 2300+ * @param $string string
 2301+ *
 2302+ * @return string
 2303+ */
 2304+ function transformUsingPairFile( $file, $string ) {
 2305+ if ( !isset( $this->transformData[$file] ) ) {
 2306+ $data = wfGetPrecompiledData( $file );
 2307+ if ( $data === false ) {
 2308+ throw new MWException( __METHOD__ . ": The transformation file $file is missing" );
 2309+ }
 2310+ $this->transformData[$file] = new ReplacementArray( $data );
 2311+ }
 2312+ return $this->transformData[$file]->replace( $string );
 2313+ }
 2314+
 2315+ /**
 2316+ * For right-to-left language support
 2317+ *
 2318+ * @return bool
 2319+ */
 2320+ function isRTL() {
 2321+ return self::$dataCache->getItem( $this->mCode, 'rtl' );
 2322+ }
 2323+
 2324+ /**
 2325+ * Return the correct HTML 'dir' attribute value for this language.
 2326+ * @return String
 2327+ */
 2328+ function getDir() {
 2329+ return $this->isRTL() ? 'rtl' : 'ltr';
 2330+ }
 2331+
 2332+ /**
 2333+ * Return 'left' or 'right' as appropriate alignment for line-start
 2334+ * for this language's text direction.
 2335+ *
 2336+ * Should be equivalent to CSS3 'start' text-align value....
 2337+ *
 2338+ * @return String
 2339+ */
 2340+ function alignStart() {
 2341+ return $this->isRTL() ? 'right' : 'left';
 2342+ }
 2343+
 2344+ /**
 2345+ * Return 'right' or 'left' as appropriate alignment for line-end
 2346+ * for this language's text direction.
 2347+ *
 2348+ * Should be equivalent to CSS3 'end' text-align value....
 2349+ *
 2350+ * @return String
 2351+ */
 2352+ function alignEnd() {
 2353+ return $this->isRTL() ? 'left' : 'right';
 2354+ }
 2355+
 2356+ /**
 2357+ * A hidden direction mark (LRM or RLM), depending on the language direction
 2358+ *
 2359+ * @return string
 2360+ */
 2361+ function getDirMark() {
 2362+ return $this->isRTL() ? "\xE2\x80\x8F" : "\xE2\x80\x8E";
 2363+ }
 2364+
 2365+ /**
 2366+ * @return array
 2367+ */
 2368+ function capitalizeAllNouns() {
 2369+ return self::$dataCache->getItem( $this->mCode, 'capitalizeAllNouns' );
 2370+ }
 2371+
 2372+ /**
 2373+ * An arrow, depending on the language direction
 2374+ *
 2375+ * @return string
 2376+ */
 2377+ function getArrow() {
 2378+ return $this->isRTL() ? 'â†�' : '→';
 2379+ }
 2380+
 2381+ /**
 2382+ * To allow "foo[[bar]]" to extend the link over the whole word "foobar"
 2383+ *
 2384+ * @return bool
 2385+ */
 2386+ function linkPrefixExtension() {
 2387+ return self::$dataCache->getItem( $this->mCode, 'linkPrefixExtension' );
 2388+ }
 2389+
 2390+ /**
 2391+ * @return array
 2392+ */
 2393+ function getMagicWords() {
 2394+ return self::$dataCache->getItem( $this->mCode, 'magicWords' );
 2395+ }
 2396+
 2397+ protected function doMagicHook() {
 2398+ if ( $this->mMagicHookDone ) {
 2399+ return;
 2400+ }
 2401+ $this->mMagicHookDone = true;
 2402+ wfProfileIn( 'LanguageGetMagic' );
 2403+ wfRunHooks( 'LanguageGetMagic', array( &$this->mMagicExtensions, $this->getCode() ) );
 2404+ wfProfileOut( 'LanguageGetMagic' );
 2405+ }
 2406+
 2407+ /**
 2408+ * Fill a MagicWord object with data from here
 2409+ *
 2410+ * @param $mw
 2411+ */
 2412+ function getMagic( $mw ) {
 2413+ $this->doMagicHook();
 2414+
 2415+ if ( isset( $this->mMagicExtensions[$mw->mId] ) ) {
 2416+ $rawEntry = $this->mMagicExtensions[$mw->mId];
 2417+ } else {
 2418+ $magicWords = $this->getMagicWords();
 2419+ if ( isset( $magicWords[$mw->mId] ) ) {
 2420+ $rawEntry = $magicWords[$mw->mId];
 2421+ } else {
 2422+ $rawEntry = false;
 2423+ }
 2424+ }
 2425+
 2426+ if ( !is_array( $rawEntry ) ) {
 2427+ error_log( "\"$rawEntry\" is not a valid magic word for \"$mw->mId\"" );
 2428+ } else {
 2429+ $mw->mCaseSensitive = $rawEntry[0];
 2430+ $mw->mSynonyms = array_slice( $rawEntry, 1 );
 2431+ }
 2432+ }
 2433+
 2434+ /**
 2435+ * Add magic words to the extension array
 2436+ *
 2437+ * @param $newWords array
 2438+ */
 2439+ function addMagicWordsByLang( $newWords ) {
 2440+ $code = $this->getCode();
 2441+ $fallbackChain = array();
 2442+ while ( $code && !in_array( $code, $fallbackChain ) ) {
 2443+ $fallbackChain[] = $code;
 2444+ $code = self::getFallbackFor( $code );
 2445+ }
 2446+ if ( !in_array( 'en', $fallbackChain ) ) {
 2447+ $fallbackChain[] = 'en';
 2448+ }
 2449+ $fallbackChain = array_reverse( $fallbackChain );
 2450+ foreach ( $fallbackChain as $code ) {
 2451+ if ( isset( $newWords[$code] ) ) {
 2452+ $this->mMagicExtensions = $newWords[$code] + $this->mMagicExtensions;
 2453+ }
 2454+ }
 2455+ }
 2456+
 2457+ /**
 2458+ * Get special page names, as an associative array
 2459+ * case folded alias => real name
 2460+ */
 2461+ function getSpecialPageAliases() {
 2462+ // Cache aliases because it may be slow to load them
 2463+ if ( is_null( $this->mExtendedSpecialPageAliases ) ) {
 2464+ // Initialise array
 2465+ $this->mExtendedSpecialPageAliases =
 2466+ self::$dataCache->getItem( $this->mCode, 'specialPageAliases' );
 2467+ wfRunHooks( 'LanguageGetSpecialPageAliases',
 2468+ array( &$this->mExtendedSpecialPageAliases, $this->getCode() ) );
 2469+ }
 2470+
 2471+ return $this->mExtendedSpecialPageAliases;
 2472+ }
 2473+
 2474+ /**
 2475+ * Italic is unsuitable for some languages
 2476+ *
 2477+ * @param $text String: the text to be emphasized.
 2478+ * @return string
 2479+ */
 2480+ function emphasize( $text ) {
 2481+ return "<em>$text</em>";
 2482+ }
 2483+
 2484+ /**
 2485+ * Normally we output all numbers in plain en_US style, that is
 2486+ * 293,291.235 for twohundredninetythreethousand-twohundredninetyone
 2487+ * point twohundredthirtyfive. However this is not sutable for all
 2488+ * languages, some such as Pakaran want ੨੯੩,੨੯੫.੨੩੫ and others such as
 2489+ * Icelandic just want to use commas instead of dots, and dots instead
 2490+ * of commas like "293.291,235".
 2491+ *
 2492+ * An example of this function being called:
 2493+ * <code>
 2494+ * wfMsg( 'message', $wgLang->formatNum( $num ) )
 2495+ * </code>
 2496+ *
 2497+ * See LanguageGu.php for the Gujarati implementation and
 2498+ * $separatorTransformTable on MessageIs.php for
 2499+ * the , => . and . => , implementation.
 2500+ *
 2501+ * @todo check if it's viable to use localeconv() for the decimal
 2502+ * separator thing.
 2503+ * @param $number Mixed: the string to be formatted, should be an integer
 2504+ * or a floating point number.
 2505+ * @param $nocommafy Bool: set to true for special numbers like dates
 2506+ * @return string
 2507+ */
 2508+ function formatNum( $number, $nocommafy = false ) {
 2509+ global $wgTranslateNumerals;
 2510+ if ( !$nocommafy ) {
 2511+ $number = $this->commafy( $number );
 2512+ $s = $this->separatorTransformTable();
 2513+ if ( $s ) {
 2514+ $number = strtr( $number, $s );
 2515+ }
 2516+ }
 2517+
 2518+ if ( $wgTranslateNumerals ) {
 2519+ $s = $this->digitTransformTable();
 2520+ if ( $s ) {
 2521+ $number = strtr( $number, $s );
 2522+ }
 2523+ }
 2524+
 2525+ return $number;
 2526+ }
 2527+
 2528+ /**
 2529+ * @param $number string
 2530+ * @return string
 2531+ */
 2532+ function parseFormattedNumber( $number ) {
 2533+ $s = $this->digitTransformTable();
 2534+ if ( $s ) {
 2535+ $number = strtr( $number, array_flip( $s ) );
 2536+ }
 2537+
 2538+ $s = $this->separatorTransformTable();
 2539+ if ( $s ) {
 2540+ $number = strtr( $number, array_flip( $s ) );
 2541+ }
 2542+
 2543+ $number = strtr( $number, array( ',' => '' ) );
 2544+ return $number;
 2545+ }
 2546+
 2547+ /**
 2548+ * Adds commas to a given number
 2549+ *
 2550+ * @param $_ mixed
 2551+ * @return string
 2552+ */
 2553+ function commafy( $_ ) {
 2554+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 2555+ }
 2556+
 2557+ /**
 2558+ * @return array
 2559+ */
 2560+ function digitTransformTable() {
 2561+ return self::$dataCache->getItem( $this->mCode, 'digitTransformTable' );
 2562+ }
 2563+
 2564+ /**
 2565+ * @return array
 2566+ */
 2567+ function separatorTransformTable() {
 2568+ return self::$dataCache->getItem( $this->mCode, 'separatorTransformTable' );
 2569+ }
 2570+
 2571+ /**
 2572+ * Take a list of strings and build a locale-friendly comma-separated
 2573+ * list, using the local comma-separator message.
 2574+ * The last two strings are chained with an "and".
 2575+ *
 2576+ * @param $l Array
 2577+ * @return string
 2578+ */
 2579+ function listToText( $l ) {
 2580+ $s = '';
 2581+ $m = count( $l ) - 1;
 2582+ if ( $m == 1 ) {
 2583+ return $l[0] . $this->getMessageFromDB( 'and' ) . $this->getMessageFromDB( 'word-separator' ) . $l[1];
 2584+ } else {
 2585+ for ( $i = $m; $i >= 0; $i-- ) {
 2586+ if ( $i == $m ) {
 2587+ $s = $l[$i];
 2588+ } elseif ( $i == $m - 1 ) {
 2589+ $s = $l[$i] . $this->getMessageFromDB( 'and' ) . $this->getMessageFromDB( 'word-separator' ) . $s;
 2590+ } else {
 2591+ $s = $l[$i] . $this->getMessageFromDB( 'comma-separator' ) . $s;
 2592+ }
 2593+ }
 2594+ return $s;
 2595+ }
 2596+ }
 2597+
 2598+ /**
 2599+ * Take a list of strings and build a locale-friendly comma-separated
 2600+ * list, using the local comma-separator message.
 2601+ * @param $list array of strings to put in a comma list
 2602+ * @return string
 2603+ */
 2604+ function commaList( $list ) {
 2605+ return implode(
 2606+ $list,
 2607+ wfMsgExt(
 2608+ 'comma-separator',
 2609+ array( 'parsemag', 'escapenoentities', 'language' => $this )
 2610+ )
 2611+ );
 2612+ }
 2613+
 2614+ /**
 2615+ * Take a list of strings and build a locale-friendly semicolon-separated
 2616+ * list, using the local semicolon-separator message.
 2617+ * @param $list array of strings to put in a semicolon list
 2618+ * @return string
 2619+ */
 2620+ function semicolonList( $list ) {
 2621+ return implode(
 2622+ $list,
 2623+ wfMsgExt(
 2624+ 'semicolon-separator',
 2625+ array( 'parsemag', 'escapenoentities', 'language' => $this )
 2626+ )
 2627+ );
 2628+ }
 2629+
 2630+ /**
 2631+ * Same as commaList, but separate it with the pipe instead.
 2632+ * @param $list array of strings to put in a pipe list
 2633+ * @return string
 2634+ */
 2635+ function pipeList( $list ) {
 2636+ return implode(
 2637+ $list,
 2638+ wfMsgExt(
 2639+ 'pipe-separator',
 2640+ array( 'escapenoentities', 'language' => $this )
 2641+ )
 2642+ );
 2643+ }
 2644+
 2645+ /**
 2646+ * Truncate a string to a specified length in bytes, appending an optional
 2647+ * string (e.g. for ellipses)
 2648+ *
 2649+ * The database offers limited byte lengths for some columns in the database;
 2650+ * multi-byte character sets mean we need to ensure that only whole characters
 2651+ * are included, otherwise broken characters can be passed to the user
 2652+ *
 2653+ * If $length is negative, the string will be truncated from the beginning
 2654+ *
 2655+ * @param $string String to truncate
 2656+ * @param $length Int: maximum length (including ellipses)
 2657+ * @param $ellipsis String to append to the truncated text
 2658+ * @param $adjustLength Boolean: Subtract length of ellipsis from $length.
 2659+ * $adjustLength was introduced in 1.18, before that behaved as if false.
 2660+ * @return string
 2661+ */
 2662+ function truncate( $string, $length, $ellipsis = '...', $adjustLength = true ) {
 2663+ # Use the localized ellipsis character
 2664+ if ( $ellipsis == '...' ) {
 2665+ $ellipsis = wfMsgExt( 'ellipsis', array( 'escapenoentities', 'language' => $this ) );
 2666+ }
 2667+ # Check if there is no need to truncate
 2668+ if ( $length == 0 ) {
 2669+ return $ellipsis; // convention
 2670+ } elseif ( strlen( $string ) <= abs( $length ) ) {
 2671+ return $string; // no need to truncate
 2672+ }
 2673+ $stringOriginal = $string;
 2674+ # If ellipsis length is >= $length then we can't apply $adjustLength
 2675+ if ( $adjustLength && strlen( $ellipsis ) >= abs( $length ) ) {
 2676+ $string = $ellipsis; // this can be slightly unexpected
 2677+ # Otherwise, truncate and add ellipsis...
 2678+ } else {
 2679+ $eLength = $adjustLength ? strlen( $ellipsis ) : 0;
 2680+ if ( $length > 0 ) {
 2681+ $length -= $eLength;
 2682+ $string = substr( $string, 0, $length ); // xyz...
 2683+ $string = $this->removeBadCharLast( $string );
 2684+ $string = $string . $ellipsis;
 2685+ } else {
 2686+ $length += $eLength;
 2687+ $string = substr( $string, $length ); // ...xyz
 2688+ $string = $this->removeBadCharFirst( $string );
 2689+ $string = $ellipsis . $string;
 2690+ }
 2691+ }
 2692+ # Do not truncate if the ellipsis makes the string longer/equal (bug 22181).
 2693+ # This check is *not* redundant if $adjustLength, due to the single case where
 2694+ # LEN($ellipsis) > ABS($limit arg); $stringOriginal could be shorter than $string.
 2695+ if ( strlen( $string ) < strlen( $stringOriginal ) ) {
 2696+ return $string;
 2697+ } else {
 2698+ return $stringOriginal;
 2699+ }
 2700+ }
 2701+
 2702+ /**
 2703+ * Remove bytes that represent an incomplete Unicode character
 2704+ * at the end of string (e.g. bytes of the char are missing)
 2705+ *
 2706+ * @param $string String
 2707+ * @return string
 2708+ */
 2709+ protected function removeBadCharLast( $string ) {
 2710+ if ( $string != '' ) {
 2711+ $char = ord( $string[strlen( $string ) - 1] );
 2712+ $m = array();
 2713+ if ( $char >= 0xc0 ) {
 2714+ # We got the first byte only of a multibyte char; remove it.
 2715+ $string = substr( $string, 0, -1 );
 2716+ } elseif ( $char >= 0x80 &&
 2717+ preg_match( '/^(.*)(?:[\xe0-\xef][\x80-\xbf]|' .
 2718+ '[\xf0-\xf7][\x80-\xbf]{1,2})$/', $string, $m ) )
 2719+ {
 2720+ # We chopped in the middle of a character; remove it
 2721+ $string = $m[1];
 2722+ }
 2723+ }
 2724+ return $string;
 2725+ }
 2726+
 2727+ /**
 2728+ * Remove bytes that represent an incomplete Unicode character
 2729+ * at the start of string (e.g. bytes of the char are missing)
 2730+ *
 2731+ * @param $string String
 2732+ * @return string
 2733+ */
 2734+ protected function removeBadCharFirst( $string ) {
 2735+ if ( $string != '' ) {
 2736+ $char = ord( $string[0] );
 2737+ if ( $char >= 0x80 && $char < 0xc0 ) {
 2738+ # We chopped in the middle of a character; remove the whole thing
 2739+ $string = preg_replace( '/^[\x80-\xbf]+/', '', $string );
 2740+ }
 2741+ }
 2742+ return $string;
 2743+ }
 2744+
 2745+ /**
 2746+ * Truncate a string of valid HTML to a specified length in bytes,
 2747+ * appending an optional string (e.g. for ellipses), and return valid HTML
 2748+ *
 2749+ * This is only intended for styled/linked text, such as HTML with
 2750+ * tags like <span> and <a>, were the tags are self-contained (valid HTML).
 2751+ * Also, this will not detect things like "display:none" CSS.
 2752+ *
 2753+ * Note: since 1.18 you do not need to leave extra room in $length for ellipses.
 2754+ *
 2755+ * @param string $text HTML string to truncate
 2756+ * @param int $length (zero/positive) Maximum length (including ellipses)
 2757+ * @param string $ellipsis String to append to the truncated text
 2758+ * @return string
 2759+ */
 2760+ function truncateHtml( $text, $length, $ellipsis = '...' ) {
 2761+ # Use the localized ellipsis character
 2762+ if ( $ellipsis == '...' ) {
 2763+ $ellipsis = wfMsgExt( 'ellipsis', array( 'escapenoentities', 'language' => $this ) );
 2764+ }
 2765+ # Check if there is clearly no need to truncate
 2766+ if ( $length <= 0 ) {
 2767+ return $ellipsis; // no text shown, nothing to format (convention)
 2768+ } elseif ( strlen( $text ) <= $length ) {
 2769+ return $text; // string short enough even *with* HTML (short-circuit)
 2770+ }
 2771+
 2772+ $displayLen = 0; // innerHTML legth so far
 2773+ $testingEllipsis = false; // checking if ellipses will make string longer/equal?
 2774+ $tagType = 0; // 0-open, 1-close
 2775+ $bracketState = 0; // 1-tag start, 2-tag name, 0-neither
 2776+ $entityState = 0; // 0-not entity, 1-entity
 2777+ $tag = $ret = $pRet = ''; // accumulated tag name, accumulated result string
 2778+ $openTags = array(); // open tag stack
 2779+ $pOpenTags = array();
 2780+
 2781+ $textLen = strlen( $text );
 2782+ $neLength = max( 0, $length - strlen( $ellipsis ) ); // non-ellipsis len if truncated
 2783+ for ( $pos = 0; true; ++$pos ) {
 2784+ # Consider truncation once the display length has reached the maximim.
 2785+ # Check that we're not in the middle of a bracket/entity...
 2786+ if ( $displayLen >= $neLength && $bracketState == 0 && $entityState == 0 ) {
 2787+ if ( !$testingEllipsis ) {
 2788+ $testingEllipsis = true;
 2789+ # Save where we are; we will truncate here unless there turn out to
 2790+ # be so few remaining characters that truncation is not necessary.
 2791+ $pOpenTags = $openTags; // save state
 2792+ $pRet = $ret; // save state
 2793+ } elseif ( $displayLen > $length && $displayLen > strlen( $ellipsis ) ) {
 2794+ # String in fact does need truncation, the truncation point was OK.
 2795+ $openTags = $pOpenTags; // reload state
 2796+ $ret = $this->removeBadCharLast( $pRet ); // reload state, multi-byte char fix
 2797+ $ret .= $ellipsis; // add ellipsis
 2798+ break;
 2799+ }
 2800+ }
 2801+ if ( $pos >= $textLen ) break; // extra iteration just for above checks
 2802+
 2803+ # Read the next char...
 2804+ $ch = $text[$pos];
 2805+ $lastCh = $pos ? $text[$pos - 1] : '';
 2806+ $ret .= $ch; // add to result string
 2807+ if ( $ch == '<' ) {
 2808+ $this->truncate_endBracket( $tag, $tagType, $lastCh, $openTags ); // for bad HTML
 2809+ $entityState = 0; // for bad HTML
 2810+ $bracketState = 1; // tag started (checking for backslash)
 2811+ } elseif ( $ch == '>' ) {
 2812+ $this->truncate_endBracket( $tag, $tagType, $lastCh, $openTags );
 2813+ $entityState = 0; // for bad HTML
 2814+ $bracketState = 0; // out of brackets
 2815+ } elseif ( $bracketState == 1 ) {
 2816+ if ( $ch == '/' ) {
 2817+ $tagType = 1; // close tag (e.g. "</span>")
 2818+ } else {
 2819+ $tagType = 0; // open tag (e.g. "<span>")
 2820+ $tag .= $ch;
 2821+ }
 2822+ $bracketState = 2; // building tag name
 2823+ } elseif ( $bracketState == 2 ) {
 2824+ if ( $ch != ' ' ) {
 2825+ $tag .= $ch;
 2826+ } else {
 2827+ // Name found (e.g. "<a href=..."), add on tag attributes...
 2828+ $pos += $this->truncate_skip( $ret, $text, "<>", $pos + 1 );
 2829+ }
 2830+ } elseif ( $bracketState == 0 ) {
 2831+ if ( $entityState ) {
 2832+ if ( $ch == ';' ) {
 2833+ $entityState = 0;
 2834+ $displayLen++; // entity is one displayed char
 2835+ }
 2836+ } else {
 2837+ if ( $ch == '&' ) {
 2838+ $entityState = 1; // entity found, (e.g. "&#160;")
 2839+ } else {
 2840+ $displayLen++; // this char is displayed
 2841+ // Add the next $max display text chars after this in one swoop...
 2842+ $max = ( $testingEllipsis ? $length : $neLength ) - $displayLen;
 2843+ $skipped = $this->truncate_skip( $ret, $text, "<>&", $pos + 1, $max );
 2844+ $displayLen += $skipped;
 2845+ $pos += $skipped;
 2846+ }
 2847+ }
 2848+ }
 2849+ }
 2850+ if ( $displayLen == 0 ) {
 2851+ return ''; // no text shown, nothing to format
 2852+ }
 2853+ // Close the last tag if left unclosed by bad HTML
 2854+ $this->truncate_endBracket( $tag, $text[$textLen - 1], $tagType, $openTags );
 2855+ while ( count( $openTags ) > 0 ) {
 2856+ $ret .= '</' . array_pop( $openTags ) . '>'; // close open tags
 2857+ }
 2858+ return $ret;
 2859+ }
 2860+
 2861+ /**
 2862+ * truncateHtml() helper function
 2863+ * like strcspn() but adds the skipped chars to $ret
 2864+ *
 2865+ * @param $ret
 2866+ * @param $text
 2867+ * @param $search
 2868+ * @param $start
 2869+ * @param $len
 2870+ * @return int
 2871+ */
 2872+ private function truncate_skip( &$ret, $text, $search, $start, $len = null ) {
 2873+ if ( $len === null ) {
 2874+ $len = -1; // -1 means "no limit" for strcspn
 2875+ } elseif ( $len < 0 ) {
 2876+ $len = 0; // sanity
 2877+ }
 2878+ $skipCount = 0;
 2879+ if ( $start < strlen( $text ) ) {
 2880+ $skipCount = strcspn( $text, $search, $start, $len );
 2881+ $ret .= substr( $text, $start, $skipCount );
 2882+ }
 2883+ return $skipCount;
 2884+ }
 2885+
 2886+ /**
 2887+ * truncateHtml() helper function
 2888+ * (a) push or pop $tag from $openTags as needed
 2889+ * (b) clear $tag value
 2890+ * @param String &$tag Current HTML tag name we are looking at
 2891+ * @param int $tagType (0-open tag, 1-close tag)
 2892+ * @param char $lastCh Character before the '>' that ended this tag
 2893+ * @param array &$openTags Open tag stack (not accounting for $tag)
 2894+ */
 2895+ private function truncate_endBracket( &$tag, $tagType, $lastCh, &$openTags ) {
 2896+ $tag = ltrim( $tag );
 2897+ if ( $tag != '' ) {
 2898+ if ( $tagType == 0 && $lastCh != '/' ) {
 2899+ $openTags[] = $tag; // tag opened (didn't close itself)
 2900+ } elseif ( $tagType == 1 ) {
 2901+ if ( $openTags && $tag == $openTags[count( $openTags ) - 1] ) {
 2902+ array_pop( $openTags ); // tag closed
 2903+ }
 2904+ }
 2905+ $tag = '';
 2906+ }
 2907+ }
 2908+
 2909+ /**
 2910+ * Grammatical transformations, needed for inflected languages
 2911+ * Invoked by putting {{grammar:case|word}} in a message
 2912+ *
 2913+ * @param $word string
 2914+ * @param $case string
 2915+ * @return string
 2916+ */
 2917+ function convertGrammar( $word, $case ) {
 2918+ global $wgGrammarForms;
 2919+ if ( isset( $wgGrammarForms[$this->getCode()][$case][$word] ) ) {
 2920+ return $wgGrammarForms[$this->getCode()][$case][$word];
 2921+ }
 2922+ return $word;
 2923+ }
 2924+
 2925+ /**
 2926+ * Provides an alternative text depending on specified gender.
 2927+ * Usage {{gender:username|masculine|feminine|neutral}}.
 2928+ * username is optional, in which case the gender of current user is used,
 2929+ * but only in (some) interface messages; otherwise default gender is used.
 2930+ * If second or third parameter are not specified, masculine is used.
 2931+ * These details may be overriden per language.
 2932+ *
 2933+ * @param $gender string
 2934+ * @param $forms array
 2935+ *
 2936+ * @return string
 2937+ */
 2938+ function gender( $gender, $forms ) {
 2939+ if ( !count( $forms ) ) {
 2940+ return '';
 2941+ }
 2942+ $forms = $this->preConvertPlural( $forms, 2 );
 2943+ if ( $gender === 'male' ) {
 2944+ return $forms[0];
 2945+ }
 2946+ if ( $gender === 'female' ) {
 2947+ return $forms[1];
 2948+ }
 2949+ return isset( $forms[2] ) ? $forms[2] : $forms[0];
 2950+ }
 2951+
 2952+ /**
 2953+ * Plural form transformations, needed for some languages.
 2954+ * For example, there are 3 form of plural in Russian and Polish,
 2955+ * depending on "count mod 10". See [[w:Plural]]
 2956+ * For English it is pretty simple.
 2957+ *
 2958+ * Invoked by putting {{plural:count|wordform1|wordform2}}
 2959+ * or {{plural:count|wordform1|wordform2|wordform3}}
 2960+ *
 2961+ * Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}}
 2962+ *
 2963+ * @param $count Integer: non-localized number
 2964+ * @param $forms Array: different plural forms
 2965+ * @return string Correct form of plural for $count in this language
 2966+ */
 2967+ function convertPlural( $count, $forms ) {
 2968+ if ( !count( $forms ) ) {
 2969+ return '';
 2970+ }
 2971+ $forms = $this->preConvertPlural( $forms, 2 );
 2972+
 2973+ return ( $count == 1 ) ? $forms[0] : $forms[1];
 2974+ }
 2975+
 2976+ /**
 2977+ * Checks that convertPlural was given an array and pads it to requested
 2978+ * amount of forms by copying the last one.
 2979+ *
 2980+ * @param $count Integer: How many forms should there be at least
 2981+ * @param $forms Array of forms given to convertPlural
 2982+ * @return array Padded array of forms or an exception if not an array
 2983+ */
 2984+ protected function preConvertPlural( /* Array */ $forms, $count ) {
 2985+ while ( count( $forms ) < $count ) {
 2986+ $forms[] = $forms[count( $forms ) - 1];
 2987+ }
 2988+ return $forms;
 2989+ }
 2990+
 2991+ /**
 2992+ * Maybe translate block durations. Note that this function is somewhat misnamed: it
 2993+ * deals with translating the *duration* ("1 week", "4 days", etc), not the expiry time
 2994+ * (which is an absolute timestamp).
 2995+ * @param $str String: the validated block duration in English
 2996+ * @return Somehow translated block duration
 2997+ * @see LanguageFi.php for example implementation
 2998+ */
 2999+ function translateBlockExpiry( $str ) {
 3000+ $duration = SpecialBlock::getSuggestedDurations( $this );
 3001+ foreach( $duration as $show => $value ){
 3002+ if ( strcmp( $str, $value ) == 0 ) {
 3003+ return htmlspecialchars( trim( $show ) );
 3004+ }
 3005+ }
 3006+
 3007+ // Since usually only infinite or indefinite is only on list, so try
 3008+ // equivalents if still here.
 3009+ $indefs = array( 'infinite', 'infinity', 'indefinite' );
 3010+ if ( in_array( $str, $indefs ) ) {
 3011+ foreach( $indefs as $val ) {
 3012+ $show = array_search( $val, $duration, true );
 3013+ if ( $show !== false ) {
 3014+ return htmlspecialchars( trim( $show ) );
 3015+ }
 3016+ }
 3017+ }
 3018+ // If all else fails, return the original string.
 3019+ return $str;
 3020+ }
 3021+
 3022+ /**
 3023+ * languages like Chinese need to be segmented in order for the diff
 3024+ * to be of any use
 3025+ *
 3026+ * @param $text String
 3027+ * @return String
 3028+ */
 3029+ function segmentForDiff( $text ) {
 3030+ return $text;
 3031+ }
 3032+
 3033+ /**
 3034+ * and unsegment to show the result
 3035+ *
 3036+ * @param $text String
 3037+ * @return String
 3038+ */
 3039+ function unsegmentForDiff( $text ) {
 3040+ return $text;
 3041+ }
 3042+
 3043+ /**
 3044+ * convert text to all supported variants
 3045+ *
 3046+ * @param $text string
 3047+ * @return array
 3048+ */
 3049+ function autoConvertToAllVariants( $text ) {
 3050+ return $this->mConverter->autoConvertToAllVariants( $text );
 3051+ }
 3052+
 3053+ /**
 3054+ * convert text to different variants of a language.
 3055+ *
 3056+ * @param $text string
 3057+ * @return string
 3058+ */
 3059+ function convert( $text ) {
 3060+ return $this->mConverter->convert( $text );
 3061+ }
 3062+
 3063+
 3064+ /**
 3065+ * Convert a Title object to a string in the preferred variant
 3066+ *
 3067+ * @param $title Title
 3068+ * @return string
 3069+ */
 3070+ function convertTitle( $title ) {
 3071+ return $this->mConverter->convertTitle( $title );
 3072+ }
 3073+
 3074+ /**
 3075+ * Check if this is a language with variants
 3076+ *
 3077+ * @return bool
 3078+ */
 3079+ function hasVariants() {
 3080+ return sizeof( $this->getVariants() ) > 1;
 3081+ }
 3082+
 3083+ /**
 3084+ * Put custom tags (e.g. -{ }-) around math to prevent conversion
 3085+ *
 3086+ * @param $text string
 3087+ * @return string
 3088+ */
 3089+ function armourMath( $text ) {
 3090+ return $this->mConverter->armourMath( $text );
 3091+ }
 3092+
 3093+ /**
 3094+ * Perform output conversion on a string, and encode for safe HTML output.
 3095+ * @param $text String text to be converted
 3096+ * @param $isTitle Bool whether this conversion is for the article title
 3097+ * @return string
 3098+ * @todo this should get integrated somewhere sane
 3099+ */
 3100+ function convertHtml( $text, $isTitle = false ) {
 3101+ return htmlspecialchars( $this->convert( $text, $isTitle ) );
 3102+ }
 3103+
 3104+ /**
 3105+ * @param $key string
 3106+ * @return string
 3107+ */
 3108+ function convertCategoryKey( $key ) {
 3109+ return $this->mConverter->convertCategoryKey( $key );
 3110+ }
 3111+
 3112+ /**
 3113+ * Get the list of variants supported by this language
 3114+ * see sample implementation in LanguageZh.php
 3115+ *
 3116+ * @return array an array of language codes
 3117+ */
 3118+ function getVariants() {
 3119+ return $this->mConverter->getVariants();
 3120+ }
 3121+
 3122+ /**
 3123+ * @return string
 3124+ */
 3125+ function getPreferredVariant() {
 3126+ return $this->mConverter->getPreferredVariant();
 3127+ }
 3128+
 3129+ /**
 3130+ * @return string
 3131+ */
 3132+ function getDefaultVariant() {
 3133+ return $this->mConverter->getDefaultVariant();
 3134+ }
 3135+
 3136+ /**
 3137+ * @return string
 3138+ */
 3139+ function getURLVariant() {
 3140+ return $this->mConverter->getURLVariant();
 3141+ }
 3142+
 3143+ /**
 3144+ * If a language supports multiple variants, it is
 3145+ * possible that non-existing link in one variant
 3146+ * actually exists in another variant. this function
 3147+ * tries to find it. See e.g. LanguageZh.php
 3148+ *
 3149+ * @param $link String: the name of the link
 3150+ * @param $nt Mixed: the title object of the link
 3151+ * @param $ignoreOtherCond Boolean: to disable other conditions when
 3152+ * we need to transclude a template or update a category's link
 3153+ * @return null the input parameters may be modified upon return
 3154+ */
 3155+ function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ) {
 3156+ $this->mConverter->findVariantLink( $link, $nt, $ignoreOtherCond );
 3157+ }
 3158+
 3159+ /**
 3160+ * If a language supports multiple variants, converts text
 3161+ * into an array of all possible variants of the text:
 3162+ * 'variant' => text in that variant
 3163+ *
 3164+ * @deprecated since 1.17 Use autoConvertToAllVariants()
 3165+ *
 3166+ * @param $text string
 3167+ *
 3168+ * @return string
 3169+ */
 3170+ function convertLinkToAllVariants( $text ) {
 3171+ return $this->mConverter->convertLinkToAllVariants( $text );
 3172+ }
 3173+
 3174+ /**
 3175+ * returns language specific options used by User::getPageRenderHash()
 3176+ * for example, the preferred language variant
 3177+ *
 3178+ * @return string
 3179+ */
 3180+ function getExtraHashOptions() {
 3181+ return $this->mConverter->getExtraHashOptions();
 3182+ }
 3183+
 3184+ /**
 3185+ * For languages that support multiple variants, the title of an
 3186+ * article may be displayed differently in different variants. this
 3187+ * function returns the apporiate title defined in the body of the article.
 3188+ *
 3189+ * @return string
 3190+ */
 3191+ function getParsedTitle() {
 3192+ return $this->mConverter->getParsedTitle();
 3193+ }
 3194+
 3195+ /**
 3196+ * Enclose a string with the "no conversion" tag. This is used by
 3197+ * various functions in the Parser
 3198+ *
 3199+ * @param $text String: text to be tagged for no conversion
 3200+ * @param $noParse bool
 3201+ * @return string the tagged text
 3202+ */
 3203+ function markNoConversion( $text, $noParse = false ) {
 3204+ return $this->mConverter->markNoConversion( $text, $noParse );
 3205+ }
 3206+
 3207+ /**
 3208+ * A regular expression to match legal word-trailing characters
 3209+ * which should be merged onto a link of the form [[foo]]bar.
 3210+ *
 3211+ * @return string
 3212+ */
 3213+ function linkTrail() {
 3214+ return self::$dataCache->getItem( $this->mCode, 'linkTrail' );
 3215+ }
 3216+
 3217+ /**
 3218+ * @return Language
 3219+ */
 3220+ function getLangObj() {
 3221+ return $this;
 3222+ }
 3223+
 3224+ /**
 3225+ * Get the RFC 3066 code for this language object
 3226+ *
 3227+ * @return string
 3228+ */
 3229+ function getCode() {
 3230+ return $this->mCode;
 3231+ }
 3232+
 3233+ /**
 3234+ * @param $code string
 3235+ */
 3236+ function setCode( $code ) {
 3237+ $this->mCode = $code;
 3238+ }
 3239+
 3240+ /**
 3241+ * Get the name of a file for a certain language code
 3242+ * @param $prefix string Prepend this to the filename
 3243+ * @param $code string Language code
 3244+ * @param $suffix string Append this to the filename
 3245+ * @return string $prefix . $mangledCode . $suffix
 3246+ */
 3247+ static function getFileName( $prefix = 'Language', $code, $suffix = '.php' ) {
 3248+ // Protect against path traversal
 3249+ if ( !Language::isValidCode( $code )
 3250+ || strcspn( $code, ":/\\\000" ) !== strlen( $code ) )
 3251+ {
 3252+ throw new MWException( "Invalid language code \"$code\"" );
 3253+ }
 3254+
 3255+ return $prefix . str_replace( '-', '_', ucfirst( $code ) ) . $suffix;
 3256+ }
 3257+
 3258+ /**
 3259+ * Get the language code from a file name. Inverse of getFileName()
 3260+ * @param $filename string $prefix . $languageCode . $suffix
 3261+ * @param $prefix string Prefix before the language code
 3262+ * @param $suffix string Suffix after the language code
 3263+ * @return string Language code, or false if $prefix or $suffix isn't found
 3264+ */
 3265+ static function getCodeFromFileName( $filename, $prefix = 'Language', $suffix = '.php' ) {
 3266+ $m = null;
 3267+ preg_match( '/' . preg_quote( $prefix, '/' ) . '([A-Z][a-z_]+)' .
 3268+ preg_quote( $suffix, '/' ) . '/', $filename, $m );
 3269+ if ( !count( $m ) ) {
 3270+ return false;
 3271+ }
 3272+ return str_replace( '_', '-', strtolower( $m[1] ) );
 3273+ }
 3274+
 3275+ /**
 3276+ * @param $code string
 3277+ * @return string
 3278+ */
 3279+ static function getMessagesFileName( $code ) {
 3280+ global $IP;
 3281+ return self::getFileName( "$IP/languages/messages/Messages", $code, '.php' );
 3282+ }
 3283+
 3284+ /**
 3285+ * @param $code string
 3286+ * @return string
 3287+ */
 3288+ static function getClassFileName( $code ) {
 3289+ global $IP;
 3290+ return self::getFileName( "$IP/languages/classes/Language", $code, '.php' );
 3291+ }
 3292+
 3293+ /**
 3294+ * Get the fallback for a given language
 3295+ *
 3296+ * @param $code string
 3297+ *
 3298+ * @return false|string
 3299+ */
 3300+ static function getFallbackFor( $code ) {
 3301+ if ( $code === 'en' ) {
 3302+ // Shortcut
 3303+ return false;
 3304+ } else {
 3305+ return self::getLocalisationCache()->getItem( $code, 'fallback' );
 3306+ }
 3307+ }
 3308+
 3309+ /**
 3310+ * Get all messages for a given language
 3311+ * WARNING: this may take a long time
 3312+ *
 3313+ * @param $code string
 3314+ *
 3315+ * @return array
 3316+ */
 3317+ static function getMessagesFor( $code ) {
 3318+ return self::getLocalisationCache()->getItem( $code, 'messages' );
 3319+ }
 3320+
 3321+ /**
 3322+ * Get a message for a given language
 3323+ *
 3324+ * @param $key string
 3325+ * @param $code string
 3326+ *
 3327+ * @return string
 3328+ */
 3329+ static function getMessageFor( $key, $code ) {
 3330+ return self::getLocalisationCache()->getSubitem( $code, 'messages', $key );
 3331+ }
 3332+
 3333+ /**
 3334+ * @param $talk
 3335+ * @return mixed
 3336+ */
 3337+ function fixVariableInNamespace( $talk ) {
 3338+ if ( strpos( $talk, '$1' ) === false ) {
 3339+ return $talk;
 3340+ }
 3341+
 3342+ global $wgMetaNamespace;
 3343+ $talk = str_replace( '$1', $wgMetaNamespace, $talk );
 3344+
 3345+ # Allow grammar transformations
 3346+ # Allowing full message-style parsing would make simple requests
 3347+ # such as action=raw much more expensive than they need to be.
 3348+ # This will hopefully cover most cases.
 3349+ $talk = preg_replace_callback( '/{{grammar:(.*?)\|(.*?)}}/i',
 3350+ array( &$this, 'replaceGrammarInNamespace' ), $talk );
 3351+ return str_replace( ' ', '_', $talk );
 3352+ }
 3353+
 3354+ /**
 3355+ * @param $m string
 3356+ * @return string
 3357+ */
 3358+ function replaceGrammarInNamespace( $m ) {
 3359+ return $this->convertGrammar( trim( $m[2] ), trim( $m[1] ) );
 3360+ }
 3361+
 3362+ /**
 3363+ * @throws MWException
 3364+ * @return array
 3365+ */
 3366+ static function getCaseMaps() {
 3367+ static $wikiUpperChars, $wikiLowerChars;
 3368+ if ( isset( $wikiUpperChars ) ) {
 3369+ return array( $wikiUpperChars, $wikiLowerChars );
 3370+ }
 3371+
 3372+ wfProfileIn( __METHOD__ );
 3373+ $arr = wfGetPrecompiledData( 'Utf8Case.ser' );
 3374+ if ( $arr === false ) {
 3375+ throw new MWException(
 3376+ "Utf8Case.ser is missing, please run \"make\" in the serialized directory\n" );
 3377+ }
 3378+ $wikiUpperChars = $arr['wikiUpperChars'];
 3379+ $wikiLowerChars = $arr['wikiLowerChars'];
 3380+ wfProfileOut( __METHOD__ );
 3381+ return array( $wikiUpperChars, $wikiLowerChars );
 3382+ }
 3383+
 3384+ /**
 3385+ * Decode an expiry (block, protection, etc) which has come from the DB
 3386+ *
 3387+ * @param $expiry String: Database expiry String
 3388+ * @param $format Bool|Int true to process using language functions, or TS_ constant
 3389+ * to return the expiry in a given timestamp
 3390+ * @return String
 3391+ */
 3392+ public function formatExpiry( $expiry, $format = true ) {
 3393+ static $infinity, $infinityMsg;
 3394+ if( $infinity === null ){
 3395+ $infinityMsg = wfMessage( 'infiniteblock' );
 3396+ $infinity = wfGetDB( DB_SLAVE )->getInfinity();
 3397+ }
 3398+
 3399+ if ( $expiry == '' || $expiry == $infinity ) {
 3400+ return $format === true
 3401+ ? $infinityMsg
 3402+ : $infinity;
 3403+ } else {
 3404+ return $format === true
 3405+ ? $this->timeanddate( $expiry )
 3406+ : wfTimestamp( $format, $expiry );
 3407+ }
 3408+ }
 3409+
 3410+ /**
 3411+ * @todo Document
 3412+ * @param $seconds int|float
 3413+ * @param $format String Optional, one of ("avoidseconds","avoidminutes"):
 3414+ * "avoidseconds" - don't mention seconds if $seconds >= 1 hour
 3415+ * "avoidminutes" - don't mention seconds/minutes if $seconds > 2 days
 3416+ * @return string
 3417+ */
 3418+ function formatTimePeriod( $seconds, $format = false ) {
 3419+ if ( round( $seconds * 10 ) < 100 ) {
 3420+ return $this->formatNum( sprintf( "%.1f", round( $seconds * 10 ) / 10 ) ) .
 3421+ $this->getMessageFromDB( 'seconds-abbrev' );
 3422+ } elseif ( round( $seconds ) < 60 ) {
 3423+ return $this->formatNum( round( $seconds ) ) .
 3424+ $this->getMessageFromDB( 'seconds-abbrev' );
 3425+ } elseif ( round( $seconds ) < 3600 ) {
 3426+ $minutes = floor( $seconds / 60 );
 3427+ $secondsPart = round( fmod( $seconds, 60 ) );
 3428+ if ( $secondsPart == 60 ) {
 3429+ $secondsPart = 0;
 3430+ $minutes++;
 3431+ }
 3432+ return $this->formatNum( $minutes ) . $this->getMessageFromDB( 'minutes-abbrev' ) .
 3433+ ' ' .
 3434+ $this->formatNum( $secondsPart ) . $this->getMessageFromDB( 'seconds-abbrev' );
 3435+ } elseif ( round( $seconds ) <= 2*86400 ) {
 3436+ $hours = floor( $seconds / 3600 );
 3437+ $minutes = floor( ( $seconds - $hours * 3600 ) / 60 );
 3438+ $secondsPart = round( $seconds - $hours * 3600 - $minutes * 60 );
 3439+ if ( $secondsPart == 60 ) {
 3440+ $secondsPart = 0;
 3441+ $minutes++;
 3442+ }
 3443+ if ( $minutes == 60 ) {
 3444+ $minutes = 0;
 3445+ $hours++;
 3446+ }
 3447+ $s = $this->formatNum( $hours ) . $this->getMessageFromDB( 'hours-abbrev' ) .
 3448+ ' ' .
 3449+ $this->formatNum( $minutes ) . $this->getMessageFromDB( 'minutes-abbrev' );
 3450+ if ( $format !== 'avoidseconds' ) {
 3451+ $s .= ' ' . $this->formatNum( $secondsPart ) .
 3452+ $this->getMessageFromDB( 'seconds-abbrev' );
 3453+ }
 3454+ return $s;
 3455+ } else {
 3456+ $days = floor( $seconds / 86400 );
 3457+ $s = $this->formatNum( $days ) . $this->getMessageFromDB( 'days-abbrev' ) . ' ';
 3458+ if ( $format === 'avoidminutes' ) {
 3459+ $hours = floor( ( $seconds - $days * 86400 ) / 3600 );
 3460+ $s .= $this->formatNum( $hours ) . $this->getMessageFromDB( 'hours-abbrev' );
 3461+ } else {
 3462+ $s .= $this->formatTimePeriod( $seconds - $days * 86400, $format );
 3463+ }
 3464+ return $s;
 3465+ }
 3466+ }
 3467+
 3468+ /**
 3469+ * @param $bps int
 3470+ * @return string
 3471+ */
 3472+ function formatBitrate( $bps ) {
 3473+ $units = array( 'bps', 'kbps', 'Mbps', 'Gbps' );
 3474+ if ( $bps <= 0 ) {
 3475+ return $this->formatNum( $bps ) . $units[0];
 3476+ }
 3477+ $unitIndex = floor( log10( $bps ) / 3 );
 3478+ $mantissa = $bps / pow( 1000, $unitIndex );
 3479+ if ( $mantissa < 10 ) {
 3480+ $mantissa = round( $mantissa, 1 );
 3481+ } else {
 3482+ $mantissa = round( $mantissa );
 3483+ }
 3484+ return $this->formatNum( $mantissa ) . $units[$unitIndex];
 3485+ }
 3486+
 3487+ /**
 3488+ * Format a size in bytes for output, using an appropriate
 3489+ * unit (B, KB, MB or GB) according to the magnitude in question
 3490+ *
 3491+ * @param $size Size to format
 3492+ * @return string Plain text (not HTML)
 3493+ */
 3494+ function formatSize( $size ) {
 3495+ // For small sizes no decimal places necessary
 3496+ $round = 0;
 3497+ if ( $size > 1024 ) {
 3498+ $size = $size / 1024;
 3499+ if ( $size > 1024 ) {
 3500+ $size = $size / 1024;
 3501+ // For MB and bigger two decimal places are smarter
 3502+ $round = 2;
 3503+ if ( $size > 1024 ) {
 3504+ $size = $size / 1024;
 3505+ $msg = 'size-gigabytes';
 3506+ } else {
 3507+ $msg = 'size-megabytes';
 3508+ }
 3509+ } else {
 3510+ $msg = 'size-kilobytes';
 3511+ }
 3512+ } else {
 3513+ $msg = 'size-bytes';
 3514+ }
 3515+ $size = round( $size, $round );
 3516+ $text = $this->getMessageFromDB( $msg );
 3517+ return str_replace( '$1', $this->formatNum( $size ), $text );
 3518+ }
 3519+
 3520+ /**
 3521+ * Get the conversion rule title, if any.
 3522+ *
 3523+ * @return string
 3524+ */
 3525+ function getConvRuleTitle() {
 3526+ return $this->mConverter->getConvRuleTitle();
 3527+ }
 3528+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/Language.php
___________________________________________________________________
Added: svn:eol-style
13529 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageRo.php
@@ -0,0 +1,30 @@
 2+<?php
 3+/**
 4+ * Romanian (Română)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageRo extends Language {
 9+
 10+ /**
 11+ * @param $count int
 12+ * @param $forms array
 13+ * @return string
 14+ */
 15+ function convertPlural( $count, $forms ) {
 16+ // Plural rules per
 17+ // http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ro
 18+ if ( !count( $forms ) ) { return ''; }
 19+
 20+ $forms = $this->preConvertPlural( $forms, 3 );
 21+
 22+ if ( $count == 1 ) {
 23+ $index = 0;
 24+ } elseif ( $count == 0 || $count % 100 < 20 ) {
 25+ $index = 1;
 26+ } else {
 27+ $index = 2;
 28+ }
 29+ return $forms[$index];
 30+ }
 31+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageRo.php
___________________________________________________________________
Added: svn:eol-style
132 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSma.php
@@ -0,0 +1,29 @@
 2+<?php
 3+/**
 4+ * Southern Sami (Åarjelsaemien)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageSma extends Language {
 9+
 10+ /**
 11+ * @param $count int
 12+ * @param $forms array
 13+ * @return string
 14+ */
 15+ function convertPlural( $count, $forms ) {
 16+ if ( !count( $forms ) ) { return ''; }
 17+
 18+ // plural forms per http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#sma
 19+ $forms = $this->preConvertPlural( $forms, 3 );
 20+
 21+ if ( $count == 1 ) {
 22+ $index = 1;
 23+ } elseif ( $count == 2 ) {
 24+ $index = 2;
 25+ } else {
 26+ $index = 3;
 27+ }
 28+ return $forms[$index];
 29+ }
 30+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSma.php
___________________________________________________________________
Added: svn:eol-style
131 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageZh.php
@@ -0,0 +1,94 @@
 2+<?php
 3+
 4+require_once( dirname( __FILE__ ) . '/../LanguageConverter.php' );
 5+require_once( dirname( __FILE__ ) . '/LanguageZh_hans.php' );
 6+
 7+/**
 8+ * class that handles both Traditional and Simplified Chinese
 9+ * right now it only distinguish zh_hans, zh_hant, zh_cn, zh_tw, zh_sg and zh_hk.
 10+ *
 11+ * @ingroup Language
 12+ */
 13+class LanguageZh extends LanguageZh_hans {
 14+
 15+ function __construct() {
 16+
 17+ parent::__construct();
 18+
 19+ $variants = array( 'zh', 'zh-hans', 'zh-hant', 'zh-cn', 'zh-hk', 'zh-mo', 'zh-my', 'zh-sg', 'zh-tw' );
 20+
 21+ $variantfallbacks = array(
 22+ 'zh' => array( 'zh-hans', 'zh-hant', 'zh-cn', 'zh-tw', 'zh-hk', 'zh-sg', 'zh-mo', 'zh-my' ),
 23+ 'zh-hans' => array( 'zh-cn', 'zh-sg', 'zh-my' ),
 24+ 'zh-hant' => array( 'zh-tw', 'zh-hk', 'zh-mo' ),
 25+ 'zh-cn' => array( 'zh-hans', 'zh-sg', 'zh-my' ),
 26+ 'zh-sg' => array( 'zh-hans', 'zh-cn', 'zh-my' ),
 27+ 'zh-my' => array( 'zh-hans', 'zh-sg', 'zh-cn' ),
 28+ 'zh-tw' => array( 'zh-hant', 'zh-hk', 'zh-mo' ),
 29+ 'zh-hk' => array( 'zh-hant', 'zh-mo', 'zh-tw' ),
 30+ 'zh-mo' => array( 'zh-hant', 'zh-hk', 'zh-tw' ),
 31+ );
 32+ $ml = array(
 33+ 'zh' => 'disable',
 34+ 'zh-hans' => 'unidirectional',
 35+ 'zh-hant' => 'unidirectional',
 36+ );
 37+ }
 38+
 39+ /**
 40+ * this should give much better diff info
 41+ *
 42+ * @param $text string
 43+ * @return string
 44+ */
 45+ function segmentForDiff( $text ) {
 46+ return preg_replace(
 47+ "/([\\xc0-\\xff][\\x80-\\xbf]*)/e",
 48+ "' ' .\"$1\"", $text );
 49+ }
 50+
 51+ /**
 52+ * @param $text string
 53+ * @return string
 54+ */
 55+ function unsegmentForDiff( $text ) {
 56+ return preg_replace(
 57+ "/ ([\\xc0-\\xff][\\x80-\\xbf]*)/e",
 58+ "\"$1\"", $text );
 59+ }
 60+
 61+ /**
 62+ * auto convert to zh-hans and normalize special characters.
 63+ *
 64+ * @param $string String
 65+ * @param $autoVariant String, default to 'zh-hans'
 66+ * @return String
 67+ */
 68+ function normalizeForSearch( $string, $autoVariant = 'zh-hans' ) {
 69+ wfProfileIn( __METHOD__ );
 70+
 71+ // always convert to zh-hans before indexing. it should be
 72+ // better to use zh-hans for search, since conversion from
 73+ // Traditional to Simplified is less ambiguous than the
 74+ // other way around
 75+ $s = $this->mConverter->autoConvert( $string, $autoVariant );
 76+ // LanguageZh_hans::normalizeForSearch
 77+ $s = parent::normalizeForSearch( $s );
 78+ wfProfileOut( __METHOD__ );
 79+ return $s;
 80+
 81+ }
 82+
 83+ /**
 84+ * @param $termsArray array
 85+ * @return array
 86+ */
 87+ function convertForSearchResult( $termsArray ) {
 88+ $terms = implode( '|', $termsArray );
 89+ $terms = self::convertDoubleWidth( $terms );
 90+ $terms = implode( '|', $this->mConverter->autoConvertToAllVariants( $terms ) );
 91+ $ret = array_unique( explode( '|', $terms ) );
 92+ return $ret;
 93+ }
 94+}
 95+
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageZh.php
___________________________________________________________________
Added: svn:eol-style
196 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageRu.php
@@ -0,0 +1,121 @@
 2+<?php
 3+
 4+/** Russian (русский язык)
 5+ *
 6+ * You can contact Alexander Sigachov (alexander.sigachov at Googgle Mail)
 7+ *
 8+ * @ingroup Language
 9+ */
 10+class LanguageRu extends Language {
 11+
 12+ /**
 13+ * Convert from the nominative form of a noun to some other case
 14+ * Invoked with {{grammar:case|word}}
 15+ *
 16+ * @param $word string
 17+ * @param $case string
 18+ * @return string
 19+ */
 20+ function convertGrammar( $word, $case ) {
 21+ global $wgGrammarForms;
 22+ if ( isset( $wgGrammarForms['ru'][$case][$word] ) ) {
 23+ return $wgGrammarForms['ru'][$case][$word];
 24+ }
 25+
 26+ # These rules are not perfect, but they are currently only used for site names so it doesn't
 27+ # matter if they are wrong sometimes. Just add a special case for your site name if necessary.
 28+
 29+ # join and array_slice instead mb_substr
 30+ $ar = array();
 31+ preg_match_all( '/./us', $word, $ar );
 32+ if ( !preg_match( "/[a-zA-Z_]/us", $word ) )
 33+ switch ( $case ) {
 34+ case 'genitive': # родительный падеж
 35+ if ( ( join( '', array_slice( $ar[0], -4 ) ) == 'вики' ) || ( join( '', array_slice( $ar[0], -4 ) ) == 'Вики' ) )
 36+ { }
 37+ elseif ( join( '', array_slice( $ar[0], -1 ) ) == 'ь' )
 38+ $word = join( '', array_slice( $ar[0], 0, -1 ) ) . 'я';
 39+ elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ия' )
 40+ $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ии';
 41+ elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ка' )
 42+ $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ки';
 43+ elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ти' )
 44+ $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'тей';
 45+ elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ды' )
 46+ $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'дов';
 47+ elseif ( join( '', array_slice( $ar[0], -3 ) ) == 'ник' )
 48+ $word = join( '', array_slice( $ar[0], 0, -3 ) ) . 'ника';
 49+ break;
 50+ case 'dative': # дательный падеж
 51+ # stub
 52+ break;
 53+ case 'accusative': # винительный падеж
 54+ # stub
 55+ break;
 56+ case 'instrumental': # творительный падеж
 57+ # stub
 58+ break;
 59+ case 'prepositional': # предложный падеж
 60+ # stub
 61+ break;
 62+ }
 63+ return $word;
 64+ }
 65+
 66+ /**
 67+ * Plural form transformations
 68+ *
 69+ * $forms[0] - singular form (for 1, 21, 31, 41...)
 70+ * $forms[1] - paucal form (for 2, 3, 4, 22, 23, 24, 32, 33, 34...)
 71+ * $forms[2] - plural form (for 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 26...)
 72+ *
 73+ * Examples:
 74+ * message with number
 75+ * "Сделано $1 {{PLURAL:$1|изменение|изменения|изменений}}"
 76+ * message without number
 77+ * "Действие не может быть выполнено по {{PLURAL:$1|следующей причине|следующим причинам}}:"
 78+ * @param $count int
 79+ * @param $forms array
 80+ *
 81+ * @return string
 82+ */
 83+ function convertPlural( $count, $forms ) {
 84+ if ( !count( $forms ) ) { return ''; }
 85+
 86+ // if no number with word, then use $form[0] for singular and $form[1] for plural or zero
 87+ if ( count( $forms ) === 2 ) return $count == 1 ? $forms[0] : $forms[1];
 88+
 89+ // @todo FIXME: CLDR defines 4 plural forms. Form with decimals missing.
 90+ // See http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ru
 91+ $forms = $this->preConvertPlural( $forms, 3 );
 92+
 93+ if ( $count > 10 && floor( ( $count % 100 ) / 10 ) == 1 ) {
 94+ return $forms[2];
 95+ } else {
 96+ switch ( $count % 10 ) {
 97+ case 1: return $forms[0];
 98+ case 2:
 99+ case 3:
 100+ case 4: return $forms[1];
 101+ default: return $forms[2];
 102+ }
 103+ }
 104+ }
 105+
 106+ /**
 107+ * Four-digit number should be without group commas (spaces)
 108+ * See manual of style at http://ru.wikipedia.org/wiki/Википедия:Оформление_статей
 109+ * So "1 234 567", "12 345" but "1234"
 110+ *
 111+ * @param $_ string
 112+ *
 113+ * @return string
 114+ */
 115+ function commafy( $_ ) {
 116+ if ( preg_match( '/^-?\d{1,4}(\.\d*)?$/', $_ ) ) {
 117+ return $_;
 118+ } else {
 119+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 120+ }
 121+ }
 122+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageRu.php
___________________________________________________________________
Added: svn:eol-style
1123 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageGa.php
@@ -0,0 +1,65 @@
 2+<?php
 3+
 4+/** Irish (Gaeilge)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageGa extends Language {
 9+
 10+ /**
 11+ * Convert day names
 12+ * Invoked with {{GRAMMAR:transformation|word}}
 13+ *
 14+ * @param $word string
 15+ * @param $case string
 16+ * @return string
 17+ */
 18+ function convertGrammar( $word, $case ) {
 19+ global $wgGrammarForms;
 20+ if ( isset( $wgGrammarForms['ga'][$case][$word] ) ) {
 21+ return $wgGrammarForms['ga'][$case][$word];
 22+ }
 23+
 24+ switch ( $case ) {
 25+ case 'ainmlae':
 26+ switch ( $word ) {
 27+ case 'an Domhnach':
 28+ $word = 'Dé Domhnaigh'; break;
 29+ case 'an Luan':
 30+ $word = 'Dé Luain'; break;
 31+ case 'an Mháirt':
 32+ $word = 'Dé Mháirt'; break;
 33+ case 'an Chéadaoin':
 34+ $word = 'Dé Chéadaoin'; break;
 35+ case 'an Déardaoin':
 36+ $word = 'Déardaoin'; break;
 37+ case 'an Aoine':
 38+ $word = 'Dé hAoine'; break;
 39+ case 'an Satharn':
 40+ $word = 'Dé Sathairn'; break;
 41+ }
 42+ }
 43+ return $word;
 44+ }
 45+
 46+ /**
 47+ * @param $count int
 48+ * @param $forms array
 49+ * @return string
 50+ */
 51+ function convertPlural( $count, $forms ) {
 52+ if ( !count( $forms ) ) { return ''; }
 53+
 54+ // plural forms per http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ga
 55+ $forms = $this->preConvertPlural( $forms, 3 );
 56+
 57+ if ( $count == 1 ) {
 58+ $index = 0;
 59+ } elseif ( $count == 2 ) {
 60+ $index = 1;
 61+ } else {
 62+ $index = 2;
 63+ }
 64+ return $forms[$index];
 65+ }
 66+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageGa.php
___________________________________________________________________
Added: svn:eol-style
167 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageGd.php
@@ -0,0 +1,46 @@
 2+<?php
 3+/** Scots Gaelic (Gàidhlig)
 4+ *
 5+ * @ingroup Language
 6+ *
 7+ * @author Raimond Spekking
 8+ * @author Niklas Laxström
 9+ */
 10+class LanguageGd extends Language {
 11+
 12+ /**
 13+ * Plural form transformations
 14+ * Based on this discussion: http://translatewiki.net/wiki/Thread:Support/New_plural_rules_for_Scots_Gaelic_(gd)
 15+ *
 16+ * $forms[0] - 1
 17+ * $forms[1] - 2
 18+ * $forms[2] - 11
 19+ * $forms[3] - 12
 20+ * $forms[4] - 3-10, 13-19
 21+ * $forms[5] - 0, 20, rest
 22+ *
 23+ * @param $count int
 24+ * @param $forms array
 25+ *
 26+ * @return string
 27+ */
 28+ function convertPlural( $count, $forms ) {
 29+ if ( !count( $forms ) ) { return ''; }
 30+ $forms = $this->preConvertPlural( $forms, 6 );
 31+
 32+ $count = abs( $count );
 33+ if ( $count === 1 ) {
 34+ return $forms[0];
 35+ } elseif ( $count === 2 ) {
 36+ return $forms[1];
 37+ } elseif ( $count === 11 ) {
 38+ return $forms[2];
 39+ } elseif ( $count === 12 ) {
 40+ return $forms[3];
 41+ } elseif ( ($count >= 3 && $count <= 10) || ($count >= 13 && $count <= 19) ) {
 42+ return $forms[4];
 43+ } else {
 44+ return $forms[5];
 45+ }
 46+ }
 47+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageGd.php
___________________________________________________________________
Added: svn:eol-style
148 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageBe_tarask.php
@@ -0,0 +1,90 @@
 2+<?php
 3+/** Belarusian in Taraškievica orthography (Беларуская тарашкевіца)
 4+ *
 5+ * @ingroup Language
 6+ *
 7+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
 8+ * @link http://be-x-old.wikipedia.org/wiki/Project_talk:LanguageBe_tarask.php
 9+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
 10+ * @license http://www.gnu.org/copyleft/fdl.html GNU Free Documentation License
 11+ */
 12+
 13+class LanguageBe_tarask extends Language {
 14+ /**
 15+ * Plural form transformations
 16+ *
 17+ * $wordform1 - singular form (for 1, 21, 31, 41...)
 18+ * $wordform2 - plural form (for 2, 3, 4, 22, 23, 24, 32, 33, 34...)
 19+ * $wordform3 - plural form (for 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 26...)
 20+ */
 21+
 22+ /**
 23+ * @param $count int
 24+ * @param $forms array
 25+ *
 26+ * @return string
 27+ */
 28+ function convertPlural( $count, $forms ) {
 29+ if ( !count( $forms ) ) { return ''; }
 30+
 31+ // if no number with word, then use $form[0] for singular and $form[1] for plural or zero
 32+ if ( count( $forms ) === 2 ) return $count == 1 ? $forms[0] : $forms[1];
 33+
 34+ // @todo FIXME: CLDR defines 4 plural forms instead of 3
 35+ // http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
 36+ $forms = $this->preConvertPlural( $forms, 3 );
 37+
 38+ if ( $count > 10 && floor( ( $count % 100 ) / 10 ) == 1 ) {
 39+ return $forms[2];
 40+ } else {
 41+ switch ( $count % 10 ) {
 42+ case 1: return $forms[0];
 43+ case 2:
 44+ case 3:
 45+ case 4: return $forms[1];
 46+ default: return $forms[2];
 47+ }
 48+ }
 49+ }
 50+
 51+ /**
 52+ * The Belarusian language uses apostrophe sign,
 53+ * but the characters used for this could be both U+0027 and U+2019.
 54+ * This function unifies apostrophe sign in search index values
 55+ * to enable seach using both apostrophe signs.
 56+ *
 57+ * @param $string string
 58+ *
 59+ * @return string
 60+ */
 61+ function normalizeForSearch( $string ) {
 62+ wfProfileIn( __METHOD__ );
 63+
 64+ # MySQL fulltext index doesn't grok utf-8, so we
 65+ # need to fold cases and convert to hex
 66+
 67+ # Replacing apostrophe sign U+2019 with U+0027
 68+ $s = preg_replace( '/\xe2\x80\x99/', '\'', $string );
 69+
 70+ $s = parent::normalizeForSearch( $s );
 71+
 72+ wfProfileOut( __METHOD__ );
 73+ return $s;
 74+ }
 75+
 76+ /**
 77+ * Four-digit number should be without group commas (spaces)
 78+ * So "1 234 567", "12 345" but "1234"
 79+ *
 80+ * @param $_ string
 81+ *
 82+ * @return string
 83+ */
 84+ function commafy( $_ ) {
 85+ if ( preg_match( '/^-?\d{1,4}(\.\d*)?$/', $_ ) ) {
 86+ return $_;
 87+ } else {
 88+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 89+ }
 90+ }
 91+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageBe_tarask.php
___________________________________________________________________
Added: svn:eol-style
192 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSr_ec.php
@@ -0,0 +1,31 @@
 2+<?php
 3+
 4+/**
 5+ * Serbian (cyrillic script)
 6+ *
 7+ * @ingroup Language
 8+ */
 9+class LanguageSr_ec extends Language {
 10+
 11+ /**
 12+ * @param $count int
 13+ * @param $forms array
 14+ * @return string
 15+ */
 16+ function convertPlural( $count, $forms ) {
 17+ if ( !count( $forms ) ) { return ''; }
 18+ $forms = $this->preConvertPlural( $forms, 3 );
 19+
 20+ if ( $count > 10 && floor( ( $count % 100 ) / 10 ) == 1 ) {
 21+ return $forms[2];
 22+ } else {
 23+ switch ( $count % 10 ) {
 24+ case 1: return $forms[0];
 25+ case 2:
 26+ case 3:
 27+ case 4: return $forms[1];
 28+ default: return $forms[2];
 29+ }
 30+ }
 31+ }
 32+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSr_ec.php
___________________________________________________________________
Added: svn:eol-style
133 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageKk_cyrl.php
@@ -0,0 +1,742 @@
 2+<?php
 3+/** Kazakh (Қазақша)
 4+ *
 5+ * @ingroup Language
 6+ */
 7+
 8+class LanguageKk_cyrl extends Language {
 9+
 10+ # Convert from the nominative form of a noun to some other case
 11+ # Invoked with {{GRAMMAR:case|word}}
 12+ /**
 13+ * Cases: genitive, dative, accusative, locative, ablative, comitative + possessive forms
 14+ *
 15+ * @param $word string
 16+ * @param $case stirng
 17+ *
 18+ * @return string
 19+ */
 20+ function convertGrammarKk_cyrl( $word, $case ) {
 21+ global $wgGrammarForms;
 22+ if ( isset( $wgGrammarForms['kk-kz'][$case][$word] ) ) {
 23+ return $wgGrammarForms['kk-kz'][$case][$word];
 24+ }
 25+ if ( isset( $wgGrammarForms['kk-cyrl'][$case][$word] ) ) {
 26+ return $wgGrammarForms['kk-cyrl'][$case][$word];
 27+ }
 28+ // Set up some constants...
 29+ // Vowels in last syllable
 30+ $frontVowels = array( "е", "ө", "ү", "і", "ә", "э", "я", "ё", "и" );
 31+ $backVowels = array( "а", "о", "ұ", "ы" );
 32+ $allVowels = array( "е", "ө", "ү", "і", "ә", "э", "а", "о", "ұ", "ы", "я", "ё", "и" );
 33+ // Preceding letters
 34+ $Nasals = array( "м", "н", "ң" );
 35+ $Sonants = array( "и", "й", "л", "р", "у", "ю" );
 36+ $Consonants = array( "п", "ф", "к", "қ", "т", "ш", "с", "х", "ц", "ч", "щ", "б", "в", "г", "д" );
 37+ $Sibilants = array( "ж", "з" );
 38+ $Sonorants = array( "и", "й", "л", "р", "у", "ю", "м", "н", "ң", "ж", "з" );
 39+
 40+ // Possessives
 41+ $firstPerson = array( "м", "ң" ); // 1st singular, 2nd unformal
 42+ $secondPerson = array( "з" ); // 1st plural, 2nd formal
 43+ $thirdPerson = array( "ы", "і" ); // 3rd
 44+
 45+ $lastLetter = $this->lastLetter( $word, $allVowels );
 46+ $wordEnding =& $lastLetter[0];
 47+ $wordLastVowel =& $lastLetter[1];
 48+
 49+ // Now convert the word
 50+ switch ( $case ) {
 51+ case "dc1":
 52+ case "genitive": # ilik
 53+ if ( in_array( $wordEnding, $Consonants ) ) {
 54+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 55+ $word = $word . "тің";
 56+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 57+ $word = $word . "тың";
 58+ }
 59+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Nasals ) ) {
 60+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 61+ $word = $word . "нің";
 62+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 63+ $word = $word . "ның";
 64+ }
 65+ } elseif ( in_array( $wordEnding, $Sonants ) || in_array( $wordEnding, $Sibilants ) ) {
 66+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 67+ $word = $word . "дің";
 68+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 69+ $word = $word . "дың";
 70+ }
 71+ }
 72+ break;
 73+ case "dc2":
 74+ case "dative": # barıs
 75+ if ( in_array( $wordEnding, $Consonants ) ) {
 76+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 77+ $word = $word . "ке";
 78+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 79+ $word = $word . "қа";
 80+ }
 81+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Sonorants ) ) {
 82+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 83+ $word = $word . "ге";
 84+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 85+ $word = $word . "ға";
 86+ }
 87+ }
 88+ break;
 89+ case "dc21":
 90+ case "possessive dative": # täweldık + barıs
 91+ if ( in_array( $wordEnding, $firstPerson ) ) {
 92+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 93+ $word = $word . "е";
 94+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 95+ $word = $word . "а";
 96+ }
 97+ } elseif ( in_array( $wordEnding, $secondPerson ) ) {
 98+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 99+ $word = $word . "ге";
 100+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 101+ $word = $word . "ға";
 102+ }
 103+ } elseif ( in_array( $wordEnding, $thirdPerson ) ) {
 104+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 105+ $word = $word . "не";
 106+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 107+ $word = $word . "на";
 108+ }
 109+ }
 110+ break;
 111+ case "dc3":
 112+ case "accusative": # tabıs
 113+ if ( in_array( $wordEnding, $Consonants ) ) {
 114+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 115+ $word = $word . "ті";
 116+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 117+ $word = $word . "ты";
 118+ }
 119+ } elseif ( in_array( $wordEnding, $allVowels ) ) {
 120+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 121+ $word = $word . "ні";
 122+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 123+ $word = $word . "ны";
 124+ }
 125+ } elseif ( in_array( $wordEnding, $Sonorants ) ) {
 126+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 127+ $word = $word . "ді";
 128+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 129+ $word = $word . "ды";
 130+ }
 131+ }
 132+ break;
 133+ case "dc31":
 134+ case "possessive accusative": # täweldık + tabıs
 135+ if ( in_array( $wordEnding, $firstPerson ) || in_array( $wordEnding, $secondPerson ) ) {
 136+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 137+ $word = $word . "ді";
 138+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 139+ $word = $word . "ды";
 140+ }
 141+ } elseif ( in_array( $wordEnding, $thirdPerson ) ) {
 142+ $word = $word . "н";
 143+ }
 144+ break;
 145+ case "dc4":
 146+ case "locative": # jatıs
 147+ if ( in_array( $wordEnding, $Consonants ) ) {
 148+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 149+ $word = $word . "те";
 150+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 151+ $word = $word . "та";
 152+ }
 153+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Sonorants ) ) {
 154+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 155+ $word = $word . "де";
 156+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 157+ $word = $word . "да";
 158+ }
 159+ }
 160+ break;
 161+ case "dc41":
 162+ case "possessive locative": # täweldık + jatıs
 163+ if ( in_array( $wordEnding, $firstPerson ) || in_array( $wordEnding, $secondPerson ) ) {
 164+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 165+ $word = $word . "де";
 166+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 167+ $word = $word . "да";
 168+ }
 169+ } elseif ( in_array( $wordEnding, $thirdPerson ) ) {
 170+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 171+ $word = $word . "нде";
 172+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 173+ $word = $word . "нда";
 174+ }
 175+ }
 176+ break;
 177+ case "dc5":
 178+ case "ablative": # şığıs
 179+ if ( in_array( $wordEnding, $Consonants ) ) {
 180+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 181+ $word = $word . "тен";
 182+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 183+ $word = $word . "тан";
 184+ }
 185+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Sonants ) || in_array( $wordEnding, $Sibilants ) ) {
 186+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 187+ $word = $word . "ден";
 188+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 189+ $word = $word . "дан";
 190+ }
 191+ } elseif ( in_array( $wordEnding, $Nasals ) ) {
 192+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 193+ $word = $word . "нен";
 194+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 195+ $word = $word . "нан";
 196+ }
 197+ }
 198+ break;
 199+ case "dc51":
 200+ case "possessive ablative": # täweldık + şığıs
 201+ if ( in_array( $wordEnding, $firstPerson ) || in_array( $wordEnding, $thirdPerson ) ) {
 202+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 203+ $word = $word . "нен";
 204+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 205+ $word = $word . "нан";
 206+ }
 207+ } elseif ( in_array( $wordEnding, $secondPerson ) ) {
 208+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 209+ $word = $word . "ден";
 210+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 211+ $word = $word . "дан";
 212+ }
 213+ }
 214+ break;
 215+ case "dc6":
 216+ case "comitative": # kömektes
 217+ if ( in_array( $wordEnding, $Consonants ) ) {
 218+ $word = $word . "пен";
 219+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Nasals ) || in_array( $wordEnding, $Sonants ) ) {
 220+ $word = $word . "мен";
 221+ } elseif ( in_array( $wordEnding, $Sibilants ) ) {
 222+ $word = $word . "бен";
 223+ }
 224+ break;
 225+ case "dc61":
 226+ case "possessive comitative": # täweldık + kömektes
 227+ if ( in_array( $wordEnding, $Consonants ) ) {
 228+ $word = $word . "пенен";
 229+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Nasals ) || in_array( $wordEnding, $Sonants ) ) {
 230+ $word = $word . "менен";
 231+ } elseif ( in_array( $wordEnding, $Sibilants ) ) {
 232+ $word = $word . "бенен";
 233+ }
 234+ break;
 235+ default: # dc0 #nominative #ataw
 236+ }
 237+ return $word;
 238+ }
 239+
 240+ /**
 241+ * @param $word string
 242+ * @param $case string
 243+ * @return string
 244+ */
 245+ function convertGrammarKk_latn( $word, $case ) {
 246+ global $wgGrammarForms;
 247+ if ( isset( $wgGrammarForms['kk-tr'][$case][$word] ) ) {
 248+ return $wgGrammarForms['kk-tr'][$case][$word];
 249+ }
 250+ if ( isset( $wgGrammarForms['kk-latn'][$case][$word] ) ) {
 251+ return $wgGrammarForms['kk-latn'][$case][$word];
 252+ }
 253+ // Set up some constants...
 254+ // Vowels in last syllable
 255+ $frontVowels = array( "e", "ö", "ü", "i", "ä", "é" );
 256+ $backVowels = array( "a", "o", "u", "ı" );
 257+ $allVowels = array( "e", "ö", "ü", "i", "ä", "é", "a", "o", "u", "ı" );
 258+ // Preceding letters
 259+ $Nasals = array( "m", "n", "ñ" );
 260+ $Sonants = array( "ï", "y", "ý", "l", "r", "w" );
 261+ $Consonants = array( "p", "f", "k", "q", "t", "ş", "s", "x", "c", "ç", "b", "v", "g", "d" );
 262+ $Sibilants = array( "j", "z" );
 263+ $Sonorants = array( "ï", "y", "ý", "l", "r", "w", "m", "n", "ñ", "j", "z" );
 264+
 265+ // Possessives
 266+ $firstPerson = array( "m", "ñ" ); // 1st singular, 2nd unformal
 267+ $secondPerson = array( "z" ); // 1st plural, 2nd formal
 268+ $thirdPerson = array( "ı", "i" ); // 3rd
 269+
 270+ $lastLetter = $this->lastLetter( $word, $allVowels );
 271+ $wordEnding =& $lastLetter[0];
 272+ $wordLastVowel =& $lastLetter[1];
 273+
 274+ // Now convert the word
 275+ switch ( $case ) {
 276+ case "dc1":
 277+ case "genitive": # ilik
 278+ if ( in_array( $wordEnding, $Consonants ) ) {
 279+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 280+ $word = $word . "tiñ";
 281+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 282+ $word = $word . "tıñ";
 283+ }
 284+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Nasals ) ) {
 285+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 286+ $word = $word . "niñ";
 287+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 288+ $word = $word . "nıñ";
 289+ }
 290+ } elseif ( in_array( $wordEnding, $Sonants ) || in_array( $wordEnding, $Sibilants ) ) {
 291+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 292+ $word = $word . "diñ";
 293+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 294+ $word = $word . "dıñ";
 295+ }
 296+ }
 297+ break;
 298+ case "dc2":
 299+ case "dative": # barıs
 300+ if ( in_array( $wordEnding, $Consonants ) ) {
 301+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 302+ $word = $word . "ke";
 303+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 304+ $word = $word . "qa";
 305+ }
 306+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Sonorants ) ) {
 307+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 308+ $word = $word . "ge";
 309+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 310+ $word = $word . "ğa";
 311+ }
 312+ }
 313+ break;
 314+ case "dc21":
 315+ case "possessive dative": # täweldık + barıs
 316+ if ( in_array( $wordEnding, $firstPerson ) ) {
 317+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 318+ $word = $word . "e";
 319+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 320+ $word = $word . "a";
 321+ }
 322+ } elseif ( in_array( $wordEnding, $secondPerson ) ) {
 323+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 324+ $word = $word . "ge";
 325+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 326+ $word = $word . "ğa";
 327+ }
 328+ } elseif ( in_array( $wordEnding, $thirdPerson ) ) {
 329+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 330+ $word = $word . "ne";
 331+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 332+ $word = $word . "na";
 333+ }
 334+ }
 335+ break;
 336+ case "dc3":
 337+ case "accusative": # tabıs
 338+ if ( in_array( $wordEnding, $Consonants ) ) {
 339+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 340+ $word = $word . "ti";
 341+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 342+ $word = $word . "tı";
 343+ }
 344+ } elseif ( in_array( $wordEnding, $allVowels ) ) {
 345+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 346+ $word = $word . "ni";
 347+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 348+ $word = $word . "nı";
 349+ }
 350+ } elseif ( in_array( $wordEnding, $Sonorants ) ) {
 351+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 352+ $word = $word . "di";
 353+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 354+ $word = $word . "dı";
 355+ }
 356+ }
 357+ break;
 358+ case "dc31":
 359+ case "possessive accusative": # täweldık + tabıs
 360+ if ( in_array( $wordEnding, $firstPerson ) || in_array( $wordEnding, $secondPerson ) ) {
 361+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 362+ $word = $word . "di";
 363+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 364+ $word = $word . "dı";
 365+ }
 366+ } elseif ( in_array( $wordEnding, $thirdPerson ) ) {
 367+ $word = $word . "n";
 368+ }
 369+ break;
 370+ case "dc4":
 371+ case "locative": # jatıs
 372+ if ( in_array( $wordEnding, $Consonants ) ) {
 373+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 374+ $word = $word . "te";
 375+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 376+ $word = $word . "ta";
 377+ }
 378+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Sonorants ) ) {
 379+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 380+ $word = $word . "de";
 381+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 382+ $word = $word . "da";
 383+ }
 384+ }
 385+ break;
 386+ case "dc41":
 387+ case "possessive locative": # täweldık + jatıs
 388+ if ( in_array( $wordEnding, $firstPerson ) || in_array( $wordEnding, $secondPerson ) ) {
 389+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 390+ $word = $word . "de";
 391+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 392+ $word = $word . "da";
 393+ }
 394+ } elseif ( in_array( $wordEnding, $thirdPerson ) ) {
 395+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 396+ $word = $word . "nde";
 397+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 398+ $word = $word . "nda";
 399+ }
 400+ }
 401+ break;
 402+ case "dc5":
 403+ case "ablative": # şığıs
 404+ if ( in_array( $wordEnding, $Consonants ) ) {
 405+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 406+ $word = $word . "ten";
 407+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 408+ $word = $word . "tan";
 409+ }
 410+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Sonants ) || in_array( $wordEnding, $Sibilants ) ) {
 411+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 412+ $word = $word . "den";
 413+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 414+ $word = $word . "dan";
 415+ }
 416+ } elseif ( in_array( $wordEnding, $Nasals ) ) {
 417+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 418+ $word = $word . "nen";
 419+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 420+ $word = $word . "nan";
 421+ }
 422+ }
 423+ break;
 424+ case "dc51":
 425+ case "possessive ablative": # täweldık + şığıs
 426+ if ( in_array( $wordEnding, $firstPerson ) || in_array( $wordEnding, $thirdPerson ) ) {
 427+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 428+ $word = $word . "nen";
 429+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 430+ $word = $word . "nan";
 431+ }
 432+ } elseif ( in_array( $wordEnding, $secondPerson ) ) {
 433+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 434+ $word = $word . "den";
 435+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 436+ $word = $word . "dan";
 437+ }
 438+ }
 439+ break;
 440+ case "dc6":
 441+ case "comitative": # kömektes
 442+ if ( in_array( $wordEnding, $Consonants ) ) {
 443+ $word = $word . "pen";
 444+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Nasals ) || in_array( $wordEnding, $Sonants ) ) {
 445+ $word = $word . "men";
 446+ } elseif ( in_array( $wordEnding, $Sibilants ) ) {
 447+ $word = $word . "ben";
 448+ }
 449+ break;
 450+ case "dc61":
 451+ case "possessive comitative": # täweldık + kömektes
 452+ if ( in_array( $wordEnding, $Consonants ) ) {
 453+ $word = $word . "penen";
 454+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Nasals ) || in_array( $wordEnding, $Sonants ) ) {
 455+ $word = $word . "menen";
 456+ } elseif ( in_array( $wordEnding, $Sibilants ) ) {
 457+ $word = $word . "benen";
 458+ }
 459+ break;
 460+ default: # dc0 #nominative #ataw
 461+ }
 462+ return $word;
 463+ }
 464+
 465+ /**
 466+ * @param $word string
 467+ * @param $case string
 468+ * @return string
 469+ */
 470+ function convertGrammarKk_arab( $word, $case ) {
 471+ global $wgGrammarForms;
 472+ if ( isset( $wgGrammarForms['kk-cn'][$case][$word] ) ) {
 473+ return $wgGrammarForms['kk-cn'][$case][$word];
 474+ }
 475+ if ( isset( $wgGrammarForms['kk-arab'][$case][$word] ) ) {
 476+ return $wgGrammarForms['kk-arab'][$case][$word];
 477+ }
 478+ // Set up some constants...
 479+ // Vowels in last syllable
 480+ $frontVowels = array( "ە", "ٶ", "ٷ", "ٸ", "ٵ", "ە" );
 481+ $backVowels = array( "ا", "و", "ۇ", "ى" );
 482+ $allVowels = array( "ە", "ٶ", "ٷ", "ٸ", "ٵ", "ە", "ا", "و", "ۇ", "ى" );
 483+ // Preceding letters
 484+ $Nasals = array( "م", "ن", "ڭ" );
 485+ $Sonants = array( "ي", "ي", "ل", "ر", "ۋ" );
 486+ $Consonants = array( "پ", "ف", "ك", "ق", "ت", "ش", "س", "ح", "تس", "چ", "ب", "ۆ", "گ", "د" );
 487+ $Sibilants = array( "ج", "ز" );
 488+ $Sonorants = array( "ي", "ي", "ل", "ر", "ۋ", "م", "ن", "ڭ", "ج", "ز" );
 489+
 490+ // Possessives
 491+ $firstPerson = array( "م", "ڭ" ); // 1st singular, 2nd unformal
 492+ $secondPerson = array( "ز" ); // 1st plural, 2nd formal
 493+ $thirdPerson = array( "ى", "ٸ" ); // 3rd
 494+
 495+ $lastLetter = $this->lastLetter( $word, $allVowels );
 496+ $wordEnding = $lastLetter[0];
 497+ $wordLastVowel = $lastLetter[1];
 498+
 499+ // Now convert the word
 500+ switch ( $case ) {
 501+ case "dc1":
 502+ case "genitive": # ilik
 503+ if ( in_array( $wordEnding, $Consonants ) ) {
 504+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 505+ $word = $word . "تٸڭ";
 506+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 507+ $word = $word . "تىڭ";
 508+ }
 509+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Nasals ) ) {
 510+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 511+ $word = $word . "نٸڭ";
 512+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 513+ $word = $word . "نىڭ";
 514+ }
 515+ } elseif ( in_array( $wordEnding, $Sonants ) || in_array( $wordEnding, $Sibilants ) ) {
 516+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 517+ $word = $word . "دٸڭ";
 518+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 519+ $word = $word . "دىڭ";
 520+ }
 521+ }
 522+ break;
 523+ case "dc2":
 524+ case "dative": # barıs
 525+ if ( in_array( $wordEnding, $Consonants ) ) {
 526+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 527+ $word = $word . "كە";
 528+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 529+ $word = $word . "قا";
 530+ }
 531+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Sonorants ) ) {
 532+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 533+ $word = $word . "گە";
 534+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 535+ $word = $word . "عا";
 536+ }
 537+ }
 538+ break;
 539+ case "dc21":
 540+ case "possessive dative": # täweldık + barıs
 541+ if ( in_array( $wordEnding, $firstPerson ) ) {
 542+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 543+ $word = $word . "ە";
 544+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 545+ $word = $word . "ا";
 546+ }
 547+ } elseif ( in_array( $wordEnding, $secondPerson ) ) {
 548+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 549+ $word = $word . "گە";
 550+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 551+ $word = $word . "عا";
 552+ }
 553+ } elseif ( in_array( $wordEnding, $thirdPerson ) ) {
 554+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 555+ $word = $word . "نە";
 556+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 557+ $word = $word . "نا";
 558+ }
 559+ }
 560+ break;
 561+ case "dc3":
 562+ case "accusative": # tabıs
 563+ if ( in_array( $wordEnding, $Consonants ) ) {
 564+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 565+ $word = $word . "تٸ";
 566+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 567+ $word = $word . "تى";
 568+ }
 569+ } elseif ( in_array( $wordEnding, $allVowels ) ) {
 570+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 571+ $word = $word . "نٸ";
 572+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 573+ $word = $word . "نى";
 574+ }
 575+ } elseif ( in_array( $wordEnding, $Sonorants ) ) {
 576+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 577+ $word = $word . "دٸ";
 578+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 579+ $word = $word . "دى";
 580+ }
 581+ }
 582+ break;
 583+ case "dc31":
 584+ case "possessive accusative": # täweldık + tabıs
 585+ if ( in_array( $wordEnding, $firstPerson ) || in_array( $wordEnding, $secondPerson ) ) {
 586+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 587+ $word = $word . "دٸ";
 588+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 589+ $word = $word . "دى";
 590+ }
 591+ } elseif ( in_array( $wordEnding, $thirdPerson ) ) {
 592+ $word = $word . "ن";
 593+ }
 594+ break;
 595+ case "dc4":
 596+ case "locative": # jatıs
 597+ if ( in_array( $wordEnding, $Consonants ) ) {
 598+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 599+ $word = $word . "تە";
 600+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 601+ $word = $word . "تا";
 602+ }
 603+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Sonorants ) ) {
 604+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 605+ $word = $word . "دە";
 606+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 607+ $word = $word . "دا";
 608+ }
 609+ }
 610+ break;
 611+ case "dc41":
 612+ case "possessive locative": # täweldık + jatıs
 613+ if ( in_array( $wordEnding, $firstPerson ) || in_array( $wordEnding, $secondPerson ) ) {
 614+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 615+ $word = $word . "دە";
 616+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 617+ $word = $word . "دا";
 618+ }
 619+ } elseif ( in_array( $wordEnding, $thirdPerson ) ) {
 620+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 621+ $word = $word . "ندە";
 622+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 623+ $word = $word . "ندا";
 624+ }
 625+ }
 626+ break;
 627+ case "dc5":
 628+ case "ablative": # şığıs
 629+ if ( in_array( $wordEnding, $Consonants ) ) {
 630+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 631+ $word = $word . "تەن";
 632+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 633+ $word = $word . "تان";
 634+ }
 635+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Sonants ) || in_array( $wordEnding, $Sibilants ) ) {
 636+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 637+ $word = $word . "دەن";
 638+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 639+ $word = $word . "دان";
 640+ }
 641+ } elseif ( in_array( $wordEnding, $Nasals ) ) {
 642+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 643+ $word = $word . "نەن";
 644+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 645+ $word = $word . "نان";
 646+ }
 647+ }
 648+ break;
 649+ case "dc51":
 650+ case "possessive ablative": # täweldık + şığıs
 651+ if ( in_array( $wordEnding, $firstPerson ) || in_array( $wordEnding, $thirdPerson ) ) {
 652+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 653+ $word = $word . "نەن";
 654+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 655+ $word = $word . "نان";
 656+ }
 657+ } elseif ( in_array( $wordEnding, $secondPerson ) ) {
 658+ if ( in_array( $wordLastVowel, $frontVowels ) ) {
 659+ $word = $word . "دەن";
 660+ } elseif ( in_array( $wordLastVowel, $backVowels ) ) {
 661+ $word = $word . "دان";
 662+ }
 663+ }
 664+ break;
 665+ case "dc6":
 666+ case "comitative": # kömektes
 667+ if ( in_array( $wordEnding, $Consonants ) ) {
 668+ $word = $word . "پەن";
 669+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Nasals ) || in_array( $wordEnding, $Sonants ) ) {
 670+ $word = $word . "مەن";
 671+ } elseif ( in_array( $wordEnding, $Sibilants ) ) {
 672+ $word = $word . "بەن";
 673+ }
 674+ break;
 675+ case "dc61":
 676+ case "possessive comitative": # täweldık + kömektes
 677+ if ( in_array( $wordEnding, $Consonants ) ) {
 678+ $word = $word . "پەنەن";
 679+ } elseif ( in_array( $wordEnding, $allVowels ) || in_array( $wordEnding, $Nasals ) || in_array( $wordEnding, $Sonants ) ) {
 680+ $word = $word . "مەنەن";
 681+ } elseif ( in_array( $wordEnding, $Sibilants ) ) {
 682+ $word = $word . "بەنەن";
 683+ }
 684+ break;
 685+ default: # dc0 #nominative #ataw
 686+ }
 687+ return $word;
 688+ }
 689+
 690+ /**
 691+ * @param $word string
 692+ * @param $allVowels array
 693+ * @return array
 694+ */
 695+ function lastLetter( $word, $allVowels ) {
 696+ $lastLetter = array();
 697+
 698+ // Put the word in a form we can play with since we're using UTF-8
 699+ $ar = preg_split( '//u', parent::lc( $word ), -1, PREG_SPLIT_NO_EMPTY );
 700+
 701+ // Here's an array with the order of the letters in the word reversed
 702+ // so we can find a match quicker *shrug*
 703+ $wordReversed = array_reverse( $ar );
 704+
 705+ // Here's the last letter in the word
 706+ $lastLetter[0] = $ar[count( $ar ) - 1];
 707+
 708+ // Find the last vowel in the word
 709+ $lastLetter[1] = NULL;
 710+ foreach ( $wordReversed as $xvalue ) {
 711+ foreach ( $allVowels as $yvalue ) {
 712+ if ( strcmp( $xvalue, $yvalue ) == 0 ) {
 713+ $lastLetter[1] = $xvalue;
 714+ break;
 715+ } else {
 716+ continue;
 717+ }
 718+ }
 719+ if ( $lastLetter[1] !== NULL ) {
 720+ break;
 721+ } else {
 722+ continue;
 723+ }
 724+ }
 725+
 726+ return $lastLetter;
 727+ }
 728+
 729+ /**
 730+ * Avoid grouping whole numbers between 0 to 9999
 731+ *
 732+ * @param $_ string
 733+ *
 734+ * @return string
 735+ */
 736+ function commafy( $_ ) {
 737+ if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
 738+ return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
 739+ } else {
 740+ return $_;
 741+ }
 742+ }
 743+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageKk_cyrl.php
___________________________________________________________________
Added: svn:eol-style
1744 + native
Index: trunk/tools/ToolserverI18N/language/classes/Names.php
@@ -0,0 +1,388 @@
 2+<?php
 3+/**
 4+ * These determine things like interwikis, language selectors, and so on.
 5+ * Safe to change without running scripts on the respective sites.
 6+ *
 7+ * @ingroup Language
 8+ */
 9+/* private */ $coreLanguageNames = array(
 10+ 'aa' => 'Qafár af', # Afar
 11+ 'ab' => 'Аҧсуа', # Abkhaz, should possibly add ' бысжѡа'
 12+ 'ace' => 'Acèh', # Aceh
 13+ 'af' => 'Afrikaans', # Afrikaans
 14+ 'ak' => 'Akan', # Akan
 15+ 'aln' => 'Gegë', # Gheg Albanian
 16+ 'als' => 'Alemannisch', # Alemannic -- not a valid code, for compatibility. See gsw.
 17+ 'am' => 'አማርኛ', # Amharic
 18+ 'an' => 'Aragonés', # Aragonese
 19+ 'ang' => 'Ænglisc', # Old English (Bug 23283)
 20+ 'anp' => 'अङ्गिका', # Angika
 21+ 'ar' => 'العربية', # Arabic
 22+ 'arc' => 'ܐܪܡܝܐ', # Aramaic
 23+ 'arn' => 'Mapudungun', # Mapuche, Mapudungu, Araucanian (Araucano)
 24+ 'ary' => 'Maġribi', # Moroccan Spoken Arabic
 25+ 'arz' => 'مصرى', # Egyptian Spoken Arabic
 26+ 'as' => 'অসমীয়া', # Assamese
 27+ 'ast' => 'Asturianu', # Asturian
 28+ 'av' => 'Авар', # Avar
 29+ 'avk' => 'Kotava', # Kotava
 30+ 'ay' => 'Aymar aru', # Aymara
 31+ 'az' => 'Azərbaycanca', # Azerbaijani
 32+ 'ba' => 'Башҡортса', # Bashkir
 33+ 'bar' => 'Boarisch', # Bavarian (Austro-Bavarian and South Tyrolean)
 34+ 'bat-smg' => 'Žemaitėška', # Samogitian (deprecated code, 'sgs' in ISO 693-3 since 2010-06-30 )
 35+ 'bcc' => 'بلوچی مکرانی', # Southern Balochi
 36+ 'bcl' => 'Bikol Central', # Bikol: Central Bicolano language
 37+ 'be' => 'Беларуская', # Belarusian normative
 38+ 'be-tarask' => "\xE2\x80\xAAБеларуская (тарашкевіца)\xE2\x80\xAC", # Belarusian in Taraskievica orthography
 39+ 'be-x-old' => "\xE2\x80\xAAБеларуская (тарашкевіца)\xE2\x80\xAC", # Belarusian in Taraskievica orthography; compat link
 40+ 'bg' => 'Български', # Bulgarian
 41+ 'bh' => 'भोजपुरी', # Bihari marco language. Falls back to Bhojpuri (bho).
 42+ 'bho' => 'भोजपुरी', # Bhojpuri
 43+ 'bi' => 'Bislama', # Bislama
 44+ 'bjn' => 'Bahasa Banjar', # Banjarese
 45+ 'bm' => 'Bamanankan', # Bambara
 46+ 'bn' => 'বাংলা', # Bengali
 47+ 'bo' => 'བོད་ཡིག', # Tibetan
 48+ 'bpy' => 'ইমার ঠার/বিষ্ণুপ্রিয়া মণিপুরী', # Bishnupriya Manipuri
 49+ 'bqi' => 'بختياري', # Bakthiari
 50+ 'br' => 'Brezhoneg', # Breton
 51+ 'brh' => 'Bráhuí', # Brahui
 52+ 'bs' => 'Bosanski', # Bosnian
 53+ 'bug' => 'ᨅᨔ ᨕᨘᨁᨗ', # Bugis
 54+ 'bxr' => 'Буряад', # Buryat (Russia)
 55+ 'ca' => 'Català', # Catalan
 56+ 'cbk-zam' => 'Chavacano de Zamboanga', # Zamboanga Chavacano
 57+ 'cdo' => 'Mìng-dĕ̤ng-ngṳ̄', # Min Dong
 58+ 'ce' => 'Нохчийн', # Chechen
 59+ 'ceb' => 'Cebuano', # Cebuano
 60+ 'ch' => 'Chamoru', # Chamorro
 61+ 'cho' => 'Choctaw', # Choctaw
 62+ 'chr' => 'ᏣᎳᎩ', # Cherokee
 63+ 'chy' => 'Tsetsêhestâhese', # Cheyenne
 64+ 'ckb' => 'کوردی', # Sorani
 65+ 'co' => 'Corsu', # Corsican
 66+ 'cps' => 'Capiceño', # Capiznon
 67+ 'cr' => 'Nēhiyawēwin / ᓀᐦᐃᔭᐍᐏᐣ', # Cree
 68+ 'crh' => 'Qırımtatarca', # Crimean Tatar (multiple scripts - defaults to Latin)
 69+ 'crh-latn' => "\xE2\x80\xAAQırımtatarca (Latin)\xE2\x80\xAC", # Crimean Tatar (Latin)
 70+ 'crh-cyrl' => "\xE2\x80\xAAКъырымтатарджа (Кирилл)\xE2\x80\xAC", # Crimean Tatar (Cyrillic)
 71+ 'cs' => 'Česky', # Czech
 72+ 'csb' => 'Kaszëbsczi', # Cassubian
 73+ 'cu' => 'Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ', # Old Church Slavonic (ancient language)
 74+ 'cv' => 'Чӑвашла', # Chuvash
 75+ 'cy' => 'Cymraeg', # Welsh
 76+ 'da' => 'Dansk', # Danish
 77+ 'de' => 'Deutsch', # German ("Du")
 78+ 'de-at' => 'Österreichisches Deutsch', # Austrian German
 79+ 'de-ch' => 'Schweizer Hochdeutsch', # Swiss Standard German
 80+ 'de-formal' => "\xE2\x80\xAADeutsch (Sie-Form)\xE2\x80\xAC", # German - formal address ("Sie")
 81+ 'diq' => 'Zazaki', # Zazaki
 82+ 'dsb' => 'Dolnoserbski', # Lower Sorbian
 83+ 'dtp' => 'Dusun Bundu-liwan', # Central Dusun
 84+ 'dv' => 'ދިވެހިބަސް', # Dhivehi
 85+ 'dz' => 'ཇོང་ཁ', # Bhutani
 86+ 'ee' => 'Eʋegbe', # Éwé
 87+ 'el' => 'Ελληνικά', # Greek
 88+ 'eml' => 'Emiliàn e rumagnòl', # Emiliano-Romagnolo / Sammarinese
 89+ 'en' => 'English', # English
 90+ 'en-gb' => 'British English', # British English
 91+ 'eo' => 'Esperanto', # Esperanto
 92+ 'es' => 'Español', # Spanish
 93+ 'et' => 'Eesti', # Estonian
 94+ 'eu' => 'Euskara', # Basque
 95+ 'ext' => 'Estremeñu', # Extremaduran
 96+ 'fa' => 'فارسی', # Persian
 97+ 'ff' => 'Fulfulde', # Fulfulde, Maasina
 98+ 'fi' => 'Suomi', # Finnish
 99+ 'fiu-vro' => 'Võro', # Võro (deprecated code, 'vro' in ISO 639-3 since 2009-01-16)
 100+ 'fj' => 'Na Vosa Vakaviti', # Fijian
 101+ 'fo' => 'Føroyskt', # Faroese
 102+ 'fr' => 'Français', # French
 103+ 'frc' => 'Français cadien', # Cajun French
 104+ 'frp' => 'Arpetan', # Franco-Provençal/Arpitan
 105+ 'frr' => 'Nordfriisk', # North Frisian
 106+ 'fur' => 'Furlan', # Friulian
 107+ 'fy' => 'Frysk', # Frisian
 108+ 'ga' => 'Gaeilge', # Irish
 109+ 'gag' => 'Gagauz', # Gagauz
 110+ 'gan' => '贛語', # Gan (multiple scripts - defaults to Traditional)
 111+ 'gan-hans' => "\xE2\x80\xAA赣语(简体)\xE2\x80\xAC", # Gan (Simplified Han)
 112+ 'gan-hant' => "\xE2\x80\xAA贛語(繁體)\xE2\x80\xAC", # Gan (Traditional Han)
 113+ 'gd' => 'Gàidhlig', # Scots Gaelic
 114+ 'gl' => 'Galego', # Galician
 115+ 'glk' => 'گیلکی', # Gilaki
 116+ 'gn' => 'Avañe\'ẽ', # Guaraní, Paraguayan
 117+ 'got' => '𐌲𐌿𐍄𐌹𐍃𐌺', # Gothic
 118+ 'grc' => 'Ἀρχαία ἑλληνικὴ', # Ancient Greek
 119+ 'gsw' => 'Alemannisch', # Alemannic
 120+ 'gu' => 'ગુજરાતી', # Gujarati
 121+ 'gv' => 'Gaelg', # Manx
 122+ 'ha' => 'هَوُسَ', # Hausa
 123+ 'hak' => 'Hak-kâ-fa', # Hakka
 124+ 'haw' => 'Hawai`i', # Hawaiian
 125+ 'he' => 'עברית', # Hebrew
 126+ 'hi' => 'हिन्दी', # Hindi
 127+ 'hif' => 'Fiji Hindi', # Fijian Hindi (multiple scripts - defaults to Latin)
 128+ 'hif-latn' => 'Fiji Hindi', # Fiji Hindi (latin)
 129+ 'hil' => 'Ilonggo', # Hiligaynon
 130+ 'ho' => 'Hiri Motu', # Hiri Motu
 131+ 'hr' => 'Hrvatski', # Croatian
 132+ 'hsb' => 'Hornjoserbsce', # Upper Sorbian
 133+ 'ht' => 'Kreyòl ayisyen', # Haitian Creole French
 134+ 'hu' => 'Magyar', # Hungarian
 135+ 'hy' => 'Հայերեն', # Armenian
 136+ 'hz' => 'Otsiherero', # Herero
 137+ 'ia' => 'Interlingua', # Interlingua (IALA)
 138+ 'id' => 'Bahasa Indonesia', # Indonesian
 139+ 'ie' => 'Interlingue', # Interlingue (Occidental)
 140+ 'ig' => 'Igbo', # Igbo
 141+ 'ii' => 'ꆇꉙ', # Sichuan Yi
 142+ 'ik' => 'Iñupiak', # Inupiak (Inupiatun, Northwest Alaska / Inupiatun, North Alaskan)
 143+ 'ike-cans' => 'ᐃᓄᒃᑎᑐᑦ', # Inuktitut, Eastern Canadian/Eastern Canadian "Eskimo"/"Eastern Arctic Eskimo"/Inuit (Unified Canadian Aboriginal Syllabics)
 144+ 'ike-latn' => 'inuktitut', # Inuktitut, Eastern Canadian (Latin script)
 145+ 'ilo' => 'Ilokano', # Ilokano
 146+ 'inh' => 'ГІалгІай Ğalğaj', # Ingush
 147+ 'io' => 'Ido', # Ido
 148+ 'is' => 'Íslenska', # Icelandic
 149+ 'it' => 'Italiano', # Italian
 150+ 'iu' => 'ᐃᓄᒃᑎᑐᑦ/inuktitut', # Inuktitut (macro language - do no localise, see ike/ikt - falls back to ike-cans)
 151+ 'ja' => '日本語', # Japanese
 152+ 'jam' => 'Patios', # Jamaican Creole English
 153+ 'jbo' => 'Lojban', # Lojban
 154+ 'jut' => 'Jysk', # Jutish / Jutlandic
 155+ 'jv' => 'Basa Jawa', # Javanese
 156+ 'ka' => 'ქართული', # Georgian
 157+ 'kaa' => 'Qaraqalpaqsha', # Karakalpak
 158+ 'kab' => 'Taqbaylit', # Kabyle
 159+ 'kbd' => 'Къэбэрдеибзэ / Qabardjajəbza', # Kabardian (multiple scripts - defaults to Cyrillic)
 160+ 'kbd-cyrl' => 'къэбэрдеибзэ', # Kabardian (Cyrillic)
 161+ 'kg' => 'Kongo', # Kongo, (FIXME!) should probaly be KiKongo or KiKoongo
 162+ 'khw' => 'کھوار', # Khowar
 163+ 'ki' => 'Gĩkũyũ', # Gikuyu
 164+ 'kiu' => 'Kırmancki', # Kirmanjki
 165+ 'kj' => 'Kwanyama', # Kwanyama
 166+ 'kk' => 'Қазақша', # Kazakh (multiple scripts - defaults to Cyrillic)
 167+ 'kk-arab' => "\xE2\x80\xABقازاقشا (تٴوتە)\xE2\x80\xAC", # Kazakh Arabic
 168+ 'kk-cyrl' => "\xE2\x80\xAAҚазақша (кирил)\xE2\x80\xAC", # Kazakh Cyrillic
 169+ 'kk-latn' => "\xE2\x80\xAAQazaqşa (latın)\xE2\x80\xAC", # Kazakh Latin
 170+ 'kk-cn' => "\xE2\x80\xABقازاقشا (جۇنگو)\xE2\x80\xAC", # Kazakh (China)
 171+ 'kk-kz' => "\xE2\x80\xAAҚазақша (Қазақстан)\xE2\x80\xAC", # Kazakh (Kazakhstan)
 172+ 'kk-tr' => "\xE2\x80\xAAQazaqşa (Türkïya)\xE2\x80\xAC", # Kazakh (Turkey)
 173+ 'kl' => 'Kalaallisut', # Inuktitut, Greenlandic/Greenlandic/Kalaallisut (kal)
 174+ 'km' => 'ភាសាខ្មែរ', # Khmer, Central
 175+ 'kn' => 'ಕನ್ನಡ', # Kannada
 176+ 'ko' => '한국어', # Korean
 177+ 'ko-kp' => '한국어 (조선)', # Korean (DPRK)
 178+ 'koi' => 'Перем Коми', # Komi-Permyak
 179+ 'kr' => 'Kanuri', # Kanuri, Central
 180+ 'krc' => 'Къарачай-Малкъар', # Karachay-Balkar
 181+ 'kri' => 'Krio', # Krio
 182+ 'krj' => 'Kinaray-a', # Kinaray-a
 183+ 'ks' => 'कश्मीरी - (كشميري)', # Kashmiri
 184+ 'ksh' => 'Ripoarisch', # Ripuarian
 185+ 'ku' => 'Kurdî', # Kurdish (multiple scripts - defaults to Latin)
 186+ 'ku-latn' => "\xE2\x80\xAAKurdî (latînî)\xE2\x80\xAC", # Northern Kurdish (Latin script)
 187+ 'ku-arab' => "\xE2\x80\xABكوردي (عەرەبی)\xE2\x80\xAC", # Northern Kurdish (Arabic script) (falls back to ckb)
 188+ 'kv' => 'Коми', # Komi-Zyrian (Cyrillic is common script but also written in Latin script)
 189+ 'kw' => 'Kernowek', # Cornish
 190+ 'ky' => 'Кыргызча', # Kirghiz
 191+ 'la' => 'Latina', # Latin
 192+ 'lad' => 'Ladino', # Ladino
 193+ 'lb' => 'Lëtzebuergesch', # Luxemburguish
 194+ 'lbe' => 'Лакку', # Lak
 195+ 'lez' => 'Лезги', # Lezgi
 196+ 'lfn' => 'Lingua Franca Nova', # Lingua Franca Nova
 197+ 'lg' => 'Luganda', # Ganda
 198+ 'li' => 'Limburgs', # Limburgian
 199+ 'lij' => 'Líguru', # Ligurian
 200+ 'liv' => 'Līvõ kēļ', # Livonian
 201+ 'lmo' => 'Lumbaart', # Lombard
 202+ 'ln' => 'Lingála', # Lingala
 203+ 'lo' => 'ລາວ',# Laotian
 204+ 'loz' => 'Silozi', # Lozi
 205+ 'lt' => 'Lietuvių', # Lithuanian
 206+ 'ltg' => 'Latgaļu', # Latgalian
 207+ 'lv' => 'Latviešu', # Latvian
 208+ 'lzh' => '文言', # Literary Chinese -- (bug 8217) lzh instead of zh-classical, http://www.sil.org/iso639-3/codes.asp?order=639_3&letter=l
 209+ 'lzz' => 'Lazuri', # Laz
 210+ 'mai' => 'मैथिली', # Maithili
 211+ 'map-bms' => 'Basa Banyumasan', # Banyumasan
 212+ 'mdf' => 'Мокшень', # Moksha
 213+ 'mg' => 'Malagasy', # Malagasy
 214+ 'mh' => 'Ebon', # Marshallese
 215+ 'mhr' => 'Олык Марий', # Eastern Mari
 216+ 'mi' => 'Māori', # Maori
 217+ 'min' => 'Baso Minangkabau', # Minangkabau
 218+ 'mk' => 'Македонски', # Macedonian
 219+ 'ml' => 'മലയാളം', # Malayalam
 220+ 'mn' => 'Монгол', # Halh Mongolian (Cyrillic) (ISO 639-3: khk)
 221+ 'mo' => 'Молдовеняскэ', # Moldovan
 222+ 'mr' => 'मराठी', # Marathi
 223+ 'mrj' => 'Кырык мары', # Hill Mari
 224+ 'ms' => 'Bahasa Melayu', # Malay
 225+ 'mt' => 'Malti', # Maltese
 226+ 'mus' => 'Mvskoke', # Muskogee/Creek
 227+ 'mwl' => 'Mirandés', # Mirandese
 228+ 'my' => 'မြန်မာဘာသာ', # Burmese
 229+ 'myv' => 'Эрзянь', # Erzya
 230+ 'mzn' => 'مازِرونی', # Mazanderani
 231+ 'na' => 'Dorerin Naoero', # Nauruan
 232+ 'nah' => 'Nāhuatl', # Nahuatl, en:Wikipedia writes Nahuatlahtolli, while another form is Náhuatl
 233+ 'nan' => 'Bân-lâm-gú', # Min-nan -- (bug 8217) nan instead of zh-min-nan, http://www.sil.org/iso639-3/codes.asp?order=639_3&letter=n
 234+ 'nap' => 'Nnapulitano', # Neapolitan
 235+ 'nb' => "\xE2\x80\xAANorsk (bokmål)\xE2\x80\xAC", # Norwegian (Bokmal)
 236+ 'nds' => 'Plattdüütsch', # Low German ''or'' Low Saxon
 237+ 'nds-nl' => 'Nedersaksisch', # Dutch Low Saxon
 238+ 'ne' => 'नेपाली', # Nepali
 239+ 'new' => 'नेपाल भाषा', # Newar / Nepal Bhasa
 240+ 'ng' => 'Oshiwambo', # Ndonga
 241+ 'niu' => 'Niuē', # Niuean
 242+ 'nl' => 'Nederlands', # Dutch
 243+ 'nl-informal' => "\xE2\x80\xAANederlands (informeel)\xE2\x80\xAC", # Dutch (informal address ("je"))
 244+ 'nn' => "\xE2\x80\xAANorsk (nynorsk)\xE2\x80\xAC", # Norwegian (Nynorsk)
 245+ 'no' => "\xE2\x80\xAANorsk (bokmål)\xE2\x80\xAC", # Norwegian
 246+ 'nov' => 'Novial', # Novial
 247+ 'nrm' => 'Nouormand', # Norman
 248+ 'nso' => 'Sesotho sa Leboa', # Northern Sotho
 249+ 'nv' => 'Diné bizaad', # Navajo
 250+ 'ny' => 'Chi-Chewa', # Chichewa
 251+ 'oc' => 'Occitan', # Occitan
 252+ 'om' => 'Oromoo', # Oromo
 253+ 'or' => 'ଓଡ଼ିଆ', # Oriya
 254+ 'os' => 'Ирон', # Ossetic -- fixed per bug 29091
 255+ 'pa' => 'ਪੰਜਾਬੀ', # Eastern Punjabi (Gurmukhi script) (pan)
 256+ 'pag' => 'Pangasinan', # Pangasinan
 257+ 'pam' => 'Kapampangan', # Pampanga
 258+ 'pap' => 'Papiamentu', # Papiamentu
 259+ 'pcd' => 'Picard', # Picard
 260+ 'pdc' => 'Deitsch', # Pennsylvania German
 261+ 'pdt' => 'Plautdietsch', # Plautdietsch/Mennonite Low German
 262+ 'pfl' => 'Pälzisch', # Palatinate German
 263+ 'pi' => 'पािऴ', # Pali
 264+ 'pih' => 'Norfuk / Pitkern', # Norfuk/Pitcairn/Norfolk
 265+ 'pl' => 'Polski', # Polish
 266+ 'pms' => 'Piemontèis', # Piedmontese
 267+ 'pnb' => 'پنجابی', # Western Punjabi
 268+ 'pnt' => 'Ποντιακά', # Pontic/Pontic Greek
 269+ 'prg' => 'Prūsiskan', # Prussian
 270+ 'ps' => 'پښتو', # Pashto, Northern/Paktu/Pakhtu/Pakhtoo/Afghan/Pakhto/Pashtu/Pushto/Yusufzai Pashto
 271+ 'pt' => 'Português', # Portuguese
 272+ 'pt-br' => 'Português do Brasil', # Brazilian Portuguese
 273+ 'qu' => 'Runa Simi', # Quechua
 274+ 'rgn' => 'Rumagnôl', # Romagnol
 275+ 'rif' => 'Tarifit', # Tarifit
 276+ 'rm' => 'Rumantsch', # Raeto-Romance
 277+ 'rmy' => 'Romani', # Vlax Romany
 278+ 'rn' => 'Kirundi', # Rundi/Kirundi/Urundi
 279+ 'ro' => 'Română', # Romanian
 280+ 'roa-rup' => 'Armãneashce', # Aromanian (deprecated code, 'rup' exists in ISO 693-3)
 281+ 'roa-tara' => 'Tarandíne', # Tarantino
 282+ 'ru' => 'Русский', # Russian
 283+ 'rue' => 'Русиньскый', # Rusyn
 284+ 'rup' => 'Armãneashce', # Aromanian
 285+ 'ruq' => 'Vlăheşte', # Megleno-Romanian (multiple scripts - defaults to Latin)
 286+ 'ruq-cyrl' => 'Влахесте', # Megleno-Romanian (Cyrillic script)
 287+ # 'ruq-grek' => 'Βλαεστε', # Megleno-Romanian (Greek script)
 288+ 'ruq-latn' => 'Vlăheşte', # Megleno-Romanian (Latin script)
 289+ 'rw' => 'Kinyarwanda', # Kinyarwanda, should possibly be Kinyarwandi
 290+ 'sa' => 'संस्कृत', # Sanskrit
 291+ 'sah' => 'Саха тыла', # Sakha
 292+ 'sc' => 'Sardu', # Sardinian
 293+ 'scn' => 'Sicilianu', # Sicilian
 294+ 'sco' => 'Scots', # Scots
 295+ 'sd' => 'سنڌي', # Sindhi
 296+ 'sdc' => 'Sassaresu', # Sassarese
 297+ 'se' => 'Sámegiella', # Northern Sami
 298+ 'sei' => 'Cmique Itom', # Seri
 299+ 'sg' => 'Sängö', # Sango/Sangho
 300+ 'sgs' => 'Žemaitėška', # Samogitian
 301+ 'sh' => 'Srpskohrvatski / Српскохрватски', # Serbocroatian
 302+ 'shi' => 'Tašlḥiyt', # Tachelhit
 303+ 'si' => 'සිංහල', # Sinhalese
 304+ 'simple' => 'Simple English', # Simple English
 305+ 'sk' => 'Slovenčina', # Slovak
 306+ 'sl' => 'Slovenščina', # Slovenian
 307+ 'sli' => 'Schläsch', # Lower Selisian
 308+ 'sm' => 'Gagana Samoa', # Samoan
 309+ 'sma' => 'Åarjelsaemien', # Southern Sami
 310+ 'sn' => 'chiShona', # Shona
 311+ 'so' => 'Soomaaliga', # Somali
 312+ 'sq' => 'Shqip', # Albanian
 313+ 'sr' => 'Српски / Srpski', # Serbian (multiple scripts - defaults to Cyrillic)
 314+ 'sr-ec' => "\xE2\x80\xAAСрпски (ћирилица)\xE2\x80\xAC", # Serbian Cyrillic ekavian
 315+ 'sr-el' => "\xE2\x80\xAASrpski (latinica)\xE2\x80\xAC", # Serbian Latin ekavian
 316+ 'srn' => 'Sranantongo', # Sranan Tongo
 317+ 'ss' => 'SiSwati', # Swati
 318+ 'st' => 'Sesotho', # Southern Sotho
 319+ 'stq' => 'Seeltersk', # Saterland Frisian
 320+ 'su' => 'Basa Sunda', # Sundanese
 321+ 'sv' => 'Svenska', # Swedish
 322+ 'sw' => 'Kiswahili', # Swahili
 323+ 'szl' => 'Ślůnski', # Silesian
 324+ 'ta' => 'தமிழ்', # Tamil
 325+ 'tcy' => 'ತುಳು', # Tulu
 326+ 'te' => 'తెలుగు', # Telugu
 327+ 'tet' => 'Tetun', # Tetun
 328+ 'tg' => 'Тоҷикӣ', # Tajiki (falls back to tg-cyrl)
 329+ 'tg-cyrl' => 'Тоҷикӣ', # Tajiki (Cyrllic script) (default)
 330+ 'tg-latn' => 'tojikī', # Tajiki (Latin script)
 331+ 'th' => 'ไทย', # Thai
 332+ 'ti' => 'ትግርኛ', # Tigrinya
 333+ 'tk' => 'Türkmençe', # Turkmen
 334+ 'tl' => 'Tagalog', # Tagalog
 335+ 'tn' => 'Setswana', # Setswana
 336+ 'to' => 'lea faka-Tonga', # Tonga (Tonga Islands)
 337+ 'tokipona' => 'Toki Pona', # Toki Pona
 338+ 'tpi' => 'Tok Pisin', # Tok Pisin
 339+ 'tr' => 'Türkçe', # Turkish
 340+ 'ts' => 'Xitsonga', # Tsonga
 341+ 'tt' => 'Татарча/Tatarça', # Tatar (multiple scripts - defaults to Cyrillic)
 342+ 'tt-cyrl' => 'Татарча', # Tatar (Cyrillic script) (default)
 343+ 'tt-latn' => 'Tatarça', # Tatar (Latin script)
 344+ 'tum' => 'chiTumbuka', # Tumbuka
 345+ 'tw' => 'Twi', # Twi, (FIXME!)
 346+ 'ty' => 'Reo Mā`ohi', # Tahitian
 347+ 'tyv' => 'Тыва дыл', # Tyvan
 348+ 'udm' => 'Удмурт', # Udmurt
 349+ 'ug' => 'ئۇيغۇرچە / Uyghurche‎', # Uyghur (multiple scripts - defaults to Arabic)
 350+ 'ug-arab' => 'ئۇيغۇرچە', # Uyghur (Arabic script) (default)
 351+ 'ug-latn' => 'Uyghurche‎', # Uyghur (Latin script)
 352+ 'uk' => 'Українська', # Ukrainian
 353+ 'ur' => 'اردو', # Urdu
 354+ 'uz' => 'O\'zbek', # Uzbek
 355+ 've' => 'Tshivenda', # Venda
 356+ 'vec' => 'Vèneto', # Venetian
 357+ 'vep' => 'Vepsan kel\'', # Veps
 358+ 'vi' => 'Tiếng Việt', # Vietnamese
 359+ 'vls' => 'West-Vlams', # West Flemish
 360+ 'vmf' => 'Mainfränkisch', # Upper Franconian, Main-Franconian
 361+ 'vo' => 'Volapük', # Volapük
 362+ 'vot' => 'Vaďďa', # Vod/Votian
 363+ 'vro' => 'Võro', # Võro
 364+ 'wa' => 'Walon', # Walloon
 365+ 'war' => 'Winaray', # Waray-Waray
 366+ 'wo' => 'Wolof', # Wolof
 367+ 'wuu' => '吴语', # Wu Chinese
 368+ 'xal' => 'Хальмг', # Kalmyk-Oirat (Kalmuk, Kalmuck, Kalmack, Qalmaq, Kalmytskii Jazyk, Khal:mag, Oirat, Volga Oirat, European Oirat, Western Mongolian)
 369+ 'xh' => 'isiXhosa', # Xhosan
 370+ 'xmf' => 'მარგალური', # Mingrelian
 371+ 'yi' => 'ייִדיש', # Yiddish
 372+ 'yo' => 'Yorùbá', # Yoruba
 373+ 'yue' => '粵語', # Cantonese -- (bug 8217) yue instead of zh-yue, http://www.sil.org/iso639-3/codes.asp?order=639_3&letter=y
 374+ 'za' => 'Vahcuengh', # Zhuang
 375+ 'zea' => 'Zeêuws', # Zeeuws/Zeaws
 376+ 'zh' => '中文', # (Zhōng Wén) - Chinese
 377+ 'zh-classical' => '文言', # Classical Chinese/Literary Chinese -- (see bug 8217)
 378+ 'zh-cn' => "\xE2\x80\xAA中文(中国大陆)\xE2\x80\xAC", # Chinese (PRC)
 379+ 'zh-hans' => "\xE2\x80\xAA中文(简体)\xE2\x80\xAC", # Mandarin Chinese (Simplified Chinese script) (cmn-hans)
 380+ 'zh-hant' => "\xE2\x80\xAA中文(繁體)\xE2\x80\xAC", # Mandarin Chinese (Traditional Chinese script) (cmn-hant)
 381+ 'zh-hk' => "\xE2\x80\xAA中文(香港)\xE2\x80\xAC", # Chinese (Hong Kong)
 382+ 'zh-min-nan' => 'Bân-lâm-gú', # Min-nan -- (see bug 8217)
 383+ 'zh-mo' => "\xE2\x80\xAA中文(澳門)\xE2\x80\xAC", # Chinese (Macau)
 384+ 'zh-my' => "\xE2\x80\xAA中文(马来西亚)\xE2\x80\xAC", # Chinese (Malaysia)
 385+ 'zh-sg' => "\xE2\x80\xAA中文(新加坡)\xE2\x80\xAC", # Chinese (Singapore)
 386+ 'zh-tw' => "\xE2\x80\xAA中文(台灣)\xE2\x80\xAC", # Chinese (Taiwan)
 387+ 'zh-yue' => '粵語', # Cantonese -- (see bug 8217)
 388+ 'zu' => 'isiZulu' # Zulu
 389+);
Property changes on: trunk/tools/ToolserverI18N/language/classes/Names.php
___________________________________________________________________
Added: svn:eol-style
1390 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageNso.php
@@ -0,0 +1,22 @@
 2+<?php
 3+/**
 4+ * Northern Sotho (Sesotho sa Leboa)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageNso extends Language {
 9+ /**
 10+ * Use singular form for zero
 11+ *
 12+ * @param $count int
 13+ * @param $forms array
 14+ *
 15+ * @return string
 16+ */
 17+ function convertPlural( $count, $forms ) {
 18+ if ( !count( $forms ) ) { return ''; }
 19+ $forms = $this->preConvertPlural( $forms, 2 );
 20+
 21+ return ( $count <= 1 ) ? $forms[0] : $forms[1];
 22+ }
 23+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageNso.php
___________________________________________________________________
Added: svn:eol-style
124 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageYue.php
@@ -0,0 +1,45 @@
 2+<?php
 3+/**
 4+ * Cantonese (粵語)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageYue extends Language {
 9+
 10+ /**
 11+ * @return bool
 12+ */
 13+ function hasWordBreaks() {
 14+ return false;
 15+ }
 16+
 17+ /**
 18+ * Eventually this should be a word segmentation;
 19+ * for now just treat each character as a word.
 20+ * @todo FIXME: Only do this for Han characters...
 21+ *
 22+ * @param $string string
 23+ * @return string
 24+ */
 25+ function segmentByWord( $string ) {
 26+ $reg = "/([\\xc0-\\xff][\\x80-\\xbf]*)/";
 27+ $s = self::insertSpace( $string, $reg );
 28+ return $s;
 29+ }
 30+
 31+ /**
 32+ * @param $string
 33+ * @return string
 34+ */
 35+ function normalizeForSearch( $string ) {
 36+ wfProfileIn( __METHOD__ );
 37+
 38+ // Double-width roman characters
 39+ $s = self::convertDoubleWidth( $string );
 40+ $s = trim( $s );
 41+ $s = parent::normalizeForSearch( $s );
 42+
 43+ wfProfileOut( __METHOD__ );
 44+ return $s;
 45+ }
 46+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageYue.php
___________________________________________________________________
Added: svn:eol-style
147 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSr_el.php
@@ -0,0 +1,33 @@
 2+<?php
 3+
 4+require_once( dirname( __FILE__ ) . '/LanguageSr_ec.php' );
 5+
 6+/**
 7+ * Serbian (latin script)
 8+ *
 9+ * @ingroup Language
 10+ */
 11+class LanguageSr_el extends Language {
 12+
 13+ /**
 14+ * @param $count int
 15+ * @param $forms array
 16+ * @return string
 17+ */
 18+ function convertPlural( $count, $forms ) {
 19+ if ( !count( $forms ) ) { return ''; }
 20+ $forms = $this->preConvertPlural( $forms, 3 );
 21+
 22+ if ( $count > 10 && floor( ( $count % 100 ) / 10 ) == 1 ) {
 23+ return $forms[2];
 24+ } else {
 25+ switch ( $count % 10 ) {
 26+ case 1: return $forms[0];
 27+ case 2:
 28+ case 3:
 29+ case 4: return $forms[1];
 30+ default: return $forms[2];
 31+ }
 32+ }
 33+ }
 34+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSr_el.php
___________________________________________________________________
Added: svn:eol-style
135 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageKk.php
@@ -0,0 +1,116 @@
 2+<?php
 3+
 4+require_once( dirname( __FILE__ ) . '/../LanguageConverter.php' );
 5+require_once( dirname( __FILE__ ) . '/LanguageKk_cyrl.php' );
 6+
 7+define( 'KK_C_UC', 'АӘБВГҒДЕЁЖЗИЙКҚЛМНҢОӨПРСТУҰҮФХҺЦЧШЩЪЫІЬЭЮЯ' ); # Kazakh Cyrillic uppercase
 8+define( 'KK_C_LC', 'аәбвгғдеёжзийкқлмнңоөпрстуұүфхһцчшщъыіьэюя' ); # Kazakh Cyrillic lowercase
 9+define( 'KK_L_UC', 'AÄBCÇDEÉFGĞHIİÏJKLMNÑOÖPQRSŞTUÜVWXYÝZ' ); # Kazakh Latin uppercase
 10+define( 'KK_L_LC', 'aäbcçdeéfgğhıiïjklmnñoöpqrsştuüvwxyýz' ); # Kazakh Latin lowercase
 11+// define( 'KK_A', 'ٴابپتجحدرزسشعفقكلمنڭەوۇۋۆىيچھ' ); # Kazakh Arabic
 12+define( 'H_HAMZA', 'ٴ' ); # U+0674 ARABIC LETTER HIGH HAMZA
 13+// define( 'ZWNJ', '‌' ); # U+200C ZERO WIDTH NON-JOINER
 14+
 15+
 16+
 17+/**
 18+ * class that handles Cyrillic, Latin and Arabic scripts for Kazakh
 19+ * right now it only distinguish kk_cyrl, kk_latn, kk_arab and kk_kz, kk_tr, kk_cn.
 20+ *
 21+ * @ingroup Language
 22+ */
 23+class LanguageKk extends LanguageKk_cyrl {
 24+
 25+ function __construct() {
 26+
 27+ parent::__construct();
 28+
 29+ $variants = array( 'kk', 'kk-cyrl', 'kk-latn', 'kk-arab', 'kk-kz', 'kk-tr', 'kk-cn' );
 30+ $variantfallbacks = array(
 31+ 'kk' => 'kk-cyrl',
 32+ 'kk-cyrl' => 'kk',
 33+ 'kk-latn' => 'kk',
 34+ 'kk-arab' => 'kk',
 35+ 'kk-kz' => 'kk-cyrl',
 36+ 'kk-tr' => 'kk-latn',
 37+ 'kk-cn' => 'kk-arab'
 38+ );
 39+ }
 40+
 41+ /**
 42+ * Work around for right-to-left direction support in kk-arab and kk-cn
 43+ *
 44+ * @return bool
 45+ */
 46+ function isRTL() {
 47+ $variant = $this->getPreferredVariant();
 48+ if ( $variant == 'kk-arab' || $variant == 'kk-cn' ) {
 49+ return true;
 50+ } else {
 51+ return parent::isRTL();
 52+ }
 53+ }
 54+
 55+ /**
 56+ * It fixes issue with ucfirst for transforming 'i' to 'İ'
 57+ *
 58+ * @param $string string
 59+ *
 60+ * @return string
 61+ */
 62+ function ucfirst ( $string ) {
 63+ $variant = $this->getPreferredVariant();
 64+ if ( ( $variant == 'kk-latn' || $variant == 'kk-tr' ) && $string[0] == 'i' ) {
 65+ $string = 'İ' . substr( $string, 1 );
 66+ } else {
 67+ $string = parent::ucfirst( $string );
 68+ }
 69+ return $string;
 70+ }
 71+
 72+ /**
 73+ * It fixes issue with lcfirst for transforming 'I' to 'ı'
 74+ *
 75+ * @param $string string
 76+ *
 77+ * @return string
 78+ */
 79+ function lcfirst ( $string ) {
 80+ $variant = $this->getPreferredVariant();
 81+ if ( ( $variant == 'kk-latn' || $variant == 'kk-tr' ) && $string[0] == 'I' ) {
 82+ $string = 'ı' . substr( $string, 1 );
 83+ } else {
 84+ $string = parent::lcfirst( $string );
 85+ }
 86+ return $string;
 87+ }
 88+
 89+ /**
 90+ * @param $word string
 91+ * @param $case string
 92+ * @return string
 93+ */
 94+ function convertGrammar( $word, $case ) {
 95+ wfProfileIn( __METHOD__ );
 96+
 97+ $variant = $this->getPreferredVariant();
 98+ switch ( $variant ) {
 99+ case 'kk-arab':
 100+ case 'kk-cn':
 101+ $word = parent::convertGrammarKk_arab( $word, $case );
 102+ break;
 103+ case 'kk-latn':
 104+ case 'kk-tr':
 105+ $word = parent::convertGrammarKk_latn( $word, $case );
 106+ break;
 107+ case 'kk-cyrl':
 108+ case 'kk-kz':
 109+ case 'kk':
 110+ default:
 111+ $word = parent::convertGrammarKk_cyrl( $word, $case );
 112+ }
 113+
 114+ wfProfileOut( __METHOD__ );
 115+ return $word;
 116+ }
 117+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageKk.php
___________________________________________________________________
Added: svn:eol-style
1118 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageCs.php
@@ -0,0 +1,34 @@
 2+<?php
 3+
 4+/** Czech (čeština [subst.], český [adj.], česky [adv.])
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageCs extends Language {
 9+
 10+ /**
 11+ * Plural transformations
 12+ * Invoked by putting
 13+ * {{plural:count|form1|form2-4|form0,5+}} for two forms plurals
 14+ * {{plural:count|form1|form0,2+}} for single form plurals
 15+ * in a message
 16+ * @param $count int
 17+ * @param $forms array
 18+ * @return string
 19+ */
 20+ function convertPlural( $count, $forms ) {
 21+ if ( !count( $forms ) ) { return ''; }
 22+ $forms = $this->preConvertPlural( $forms, 3 );
 23+
 24+ switch ( $count ) {
 25+ case 1:
 26+ return $forms[0];
 27+ case 2:
 28+ case 3:
 29+ case 4:
 30+ return $forms[1];
 31+ default:
 32+ return $forms[2];
 33+ }
 34+ }
 35+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageCs.php
___________________________________________________________________
Added: svn:eol-style
136 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSe.php
@@ -0,0 +1,29 @@
 2+<?php
 3+/**
 4+ * Northern Sami (Sámegiella)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageSe extends Language {
 9+
 10+ /**
 11+ * @param $count int
 12+ * @param $forms array
 13+ * @return string
 14+ */
 15+ function convertPlural( $count, $forms ) {
 16+ if ( !count( $forms ) ) { return ''; }
 17+
 18+ // plural forms per http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#se
 19+ $forms = $this->preConvertPlural( $forms, 3 );
 20+
 21+ if ( $count == 1 ) {
 22+ $index = 0;
 23+ } elseif ( $count == 2 ) {
 24+ $index = 1;
 25+ } else {
 26+ $index = 2;
 27+ }
 28+ return $forms[$index];
 29+ }
 30+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSe.php
___________________________________________________________________
Added: svn:eol-style
131 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageKm.php
@@ -0,0 +1,22 @@
 2+<?php
 3+/** Khmer (ភាសាខ្មែរ)
 4+ *
 5+ * @ingroup Language
 6+ *
 7+ * @author Niklas Laxström
 8+ */
 9+class LanguageKm extends Language {
 10+
 11+ /**
 12+ * @param $_ string
 13+ * @return string
 14+ */
 15+ function commafy( $_ ) {
 16+ /* NO-op for Khmer. Cannot use
 17+ * $separatorTransformTable = array( ',' => '' )
 18+ * That would break when parsing and doing strstr '' => 'foo';
 19+ */
 20+ return $_;
 21+ }
 22+
 23+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageKm.php
___________________________________________________________________
Added: svn:eol-style
124 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageCu.php
@@ -0,0 +1,61 @@
 2+<?php
 3+
 4+/** Old Church Slavonic (Ѩзыкъ словѣньскъ)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageCu extends Language {
 9+
 10+ /**
 11+ * Convert from the nominative form of a noun to some other case
 12+ * Invoked with {{grammar:case|word}}
 13+ *
 14+ * @param $word string
 15+ * @param $case string
 16+ * @return string
 17+ */
 18+ function convertGrammar( $word, $case ) {
 19+ global $wgGrammarForms;
 20+ if ( isset( $wgGrammarForms['сu'][$case][$word] ) ) {
 21+ return $wgGrammarForms['сu'][$case][$word];
 22+ }
 23+
 24+ # These rules are not perfect, but they are currently only used for site names so it doesn't
 25+ # matter if they are wrong sometimes. Just add a special case for your site name if necessary.
 26+
 27+ # join and array_slice instead mb_substr
 28+ $ar = array();
 29+ preg_match_all( '/./us', $word, $ar );
 30+ if ( !preg_match( "/[a-zA-Z_]/us", $word ) )
 31+ switch ( $case ) {
 32+ case 'genitive': # родительный падеж
 33+ if ( ( join( '', array_slice( $ar[0], -4 ) ) == 'вики' ) || ( join( '', array_slice( $ar[0], -4 ) ) == 'Вики' ) )
 34+ { }
 35+ elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ї' )
 36+ $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'їѩ';
 37+ break;
 38+ case 'accusative': # винительный падеж
 39+ # stub
 40+ break;
 41+ }
 42+ return $word;
 43+ }
 44+
 45+ /**
 46+ * @param $count int
 47+ * @param $forms array
 48+ * @return string
 49+ */
 50+ function convertPlural( $count, $forms ) {
 51+ if ( !count( $forms ) ) { return ''; }
 52+ $forms = $this->preConvertPlural( $forms, 4 );
 53+
 54+ switch ( $count % 10 ) {
 55+ case 1: return $forms[0];
 56+ case 2: return $forms[1];
 57+ case 3:
 58+ case 4: return $forms[2];
 59+ default: return $forms[3];
 60+ }
 61+ }
 62+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageCu.php
___________________________________________________________________
Added: svn:eol-style
163 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageWa.php
@@ -0,0 +1,95 @@
 2+<?php
 3+/**
 4+ * Walloon (Walon)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+
 9+# NOTE: cweri après "NOTE:" po des racsegnes so des ratournaedjes
 10+# k' i gn a.
 11+
 12+class LanguageWa extends Language {
 13+ /**
 14+ * Use singular form for zero
 15+ *
 16+ * @param $count int
 17+ * @param $forms array
 18+ *
 19+ * @return string
 20+ */
 21+ function convertPlural( $count, $forms ) {
 22+ if ( !count( $forms ) ) { return ''; }
 23+ $forms = $this->preConvertPlural( $forms, 2 );
 24+
 25+ return ( $count <= 1 ) ? $forms[0] : $forms[1];
 26+ }
 27+
 28+ /**
 29+ * Dates in Walloon are "1î d' <monthname>" for 1st of the month,
 30+ * "<day> di <monthname>" for months starting by a consoun, and
 31+ * "<day> d' <monthname>" for months starting with a vowel
 32+ *
 33+ * @param $ts string
 34+ * @param $adj bool
 35+ * @param $format bool
 36+ * @param $tc bool
 37+ * @return string
 38+ */
 39+ function date( $ts, $adj = false, $format = true, $tc = false ) {
 40+ $ts = wfTimestamp( TS_MW, $ts );
 41+ if ( $adj ) { $ts = $this->userAdjust( $ts, $tc ); }
 42+ $datePreference = $this->dateFormat( $format );
 43+
 44+ # ISO (YYYY-mm-dd) format
 45+ #
 46+ # we also output this format for YMD (eg: 2001 January 15)
 47+ if ( $datePreference == 'ISO 8601' ) {
 48+ $d = substr( $ts, 0, 4 ) . '-' . substr( $ts, 4, 2 ) . '-' . substr( $ts, 6, 2 );
 49+ return $d;
 50+ }
 51+
 52+ # dd/mm/YYYY format
 53+ if ( $datePreference == 'walloon short' ) {
 54+ $d = substr( $ts, 6, 2 ) . '/' . substr( $ts, 4, 2 ) . '/' . substr( $ts, 0, 4 );
 55+ return $d;
 56+ }
 57+
 58+ # Walloon format
 59+ #
 60+ # we output this in all other cases
 61+ $m = substr( $ts, 4, 2 );
 62+ $n = substr( $ts, 6, 2 );
 63+ if ( $n == 1 ) {
 64+ $d = "1î d' " . $this->getMonthName( $m ) .
 65+ " " . substr( $ts, 0, 4 );
 66+ } elseif ( $n == 2 || $n == 3 || $n == 20 || $n == 22 || $n == 23 ) {
 67+ $d = ( 0 + $n ) . " d' " . $this->getMonthName( $m ) .
 68+ " " . substr( $ts, 0, 4 );
 69+ } elseif ( $m == 4 || $m == 8 || $m == 10 ) {
 70+ $d = ( 0 + $n ) . " d' " . $this->getMonthName( $m ) .
 71+ " " . substr( $ts, 0, 4 );
 72+ } else {
 73+ $d = ( 0 + $n ) . " di " . $this->getMonthName( $m ) .
 74+ " " . substr( $ts, 0, 4 );
 75+ }
 76+ return $d;
 77+ }
 78+
 79+ /**
 80+ * @param $ts string
 81+ * @param $adj bool
 82+ * @param $format bool
 83+ * @param $tc bool
 84+ * @return string
 85+ */
 86+ function timeanddate( $ts, $adj = false, $format = true, $tc = false ) {
 87+ if ( $adj ) { $ts = $this->userAdjust( $ts, $tc ); }
 88+ $datePreference = $this->dateFormat( $format );
 89+ if ( $datePreference == 'ISO 8601' ) {
 90+ return parent::timeanddate( $ts, $adj, $format, $tc );
 91+ } else {
 92+ return $this->date( $ts, $adj, $format, $tc ) . ' a ' .
 93+ $this->time( $ts, $adj, $format, $tc );
 94+ }
 95+ }
 96+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageWa.php
___________________________________________________________________
Added: svn:eol-style
197 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSh.php
@@ -0,0 +1,36 @@
 2+<?php
 3+/**
 4+ * Serbo-Croatian (Srpskohrvatski / Српскохрватски)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageSh extends Language {
 9+
 10+ /**
 11+ * @param $count string
 12+ * @param $forms array
 13+ * @return string
 14+ */
 15+ function convertPlural( $count, $forms ) {
 16+ if ( !count( $forms ) ) { return ''; }
 17+
 18+ // if no number with word, then use $form[0] for singular and $form[1] for plural or zero
 19+ if ( count( $forms ) === 2 ) return $count == 1 ? $forms[0] : $forms[1];
 20+
 21+ // @todo FIXME: CLDR defines 4 plural forms. Form with decimals missing.
 22+ // See http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#sh
 23+ $forms = $this->preConvertPlural( $forms, 3 );
 24+
 25+ if ( $count > 10 && floor( ( $count % 100 ) / 10 ) == 1 ) {
 26+ return $forms[2];
 27+ } else {
 28+ switch ( $count % 10 ) {
 29+ case 1: return $forms[0];
 30+ case 2:
 31+ case 3:
 32+ case 4: return $forms[1];
 33+ default: return $forms[2];
 34+ }
 35+ }
 36+ }
 37+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSh.php
___________________________________________________________________
Added: svn:eol-style
138 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageCy.php
@@ -0,0 +1,30 @@
 2+<?php
 3+/** Welsh (Cymraeg)
 4+ *
 5+ * @ingroup Language
 6+ *
 7+ * @author Niklas Laxström
 8+ */
 9+class LanguageCy extends Language {
 10+
 11+ /**
 12+ * @param $count int
 13+ * @param $forms array
 14+ * @return string
 15+ */
 16+ function convertPlural( $count, $forms ) {
 17+ if ( !count( $forms ) ) { return ''; }
 18+
 19+ // @todo FIXME: CLDR defines 4 plural forms; very different, actually.
 20+ // See http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#cy
 21+ $forms = $this->preConvertPlural( $forms, 6 );
 22+ $count = abs( $count );
 23+ if ( $count >= 0 && $count <= 3 ) {
 24+ return $forms[$count];
 25+ } elseif ( $count == 6 ) {
 26+ return $forms[4];
 27+ } else {
 28+ return $forms[5];
 29+ }
 30+ }
 31+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageCy.php
___________________________________________________________________
Added: svn:eol-style
132 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageGv.php
@@ -0,0 +1,32 @@
 2+<?php
 3+
 4+/** Manx (Gaelg)
 5+ *
 6+ * @ingroup Language
 7+ *
 8+ * @author Niklas Laxström
 9+ */
 10+class LanguageGv extends Language {
 11+
 12+ /**
 13+ * @param $count int
 14+ * @param $forms array
 15+ * @return string
 16+ */
 17+ function convertPlural( $count, $forms ) {
 18+ if ( !count( $forms ) ) { return ''; }
 19+
 20+ $forms = $this->preConvertPlural( $forms, 4 );
 21+
 22+ if ( $count > 0 && ( $count % 20 ) === 0 ) {
 23+ return $forms[0];
 24+ } else {
 25+ switch ( $count % 10 ) {
 26+ case 1: return $forms[1];
 27+ case 2: return $forms[2];
 28+ default: return $forms[3];
 29+ }
 30+ }
 31+ }
 32+
 33+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageGv.php
___________________________________________________________________
Added: svn:eol-style
134 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSk.php
@@ -0,0 +1,27 @@
 2+<?php
 3+/**
 4+ * Slovak (Slovenčina)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageSk extends Language {
 9+
 10+ /**
 11+ * @param $count int
 12+ * @param $forms array
 13+ * @return string
 14+ */
 15+ function convertPlural( $count, $forms ) {
 16+ if ( !count( $forms ) ) { return ''; }
 17+ $forms = $this->preConvertPlural( $forms, 3 );
 18+
 19+ if ( $count == 1 ) {
 20+ $index = 0;
 21+ } elseif ( $count == 2 || $count == 3 || $count == 4 ) {
 22+ $index = 1;
 23+ } else {
 24+ $index = 2;
 25+ }
 26+ return $forms[$index];
 27+ }
 28+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSk.php
___________________________________________________________________
Added: svn:eol-style
129 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSl.php
@@ -0,0 +1,57 @@
 2+<?php
 3+
 4+/** Slovenian (Slovenščina)
 5+ *
 6+ * @ingroup Language
 7+ */
 8+class LanguageSl extends Language {
 9+ # Convert from the nominative form of a noun to some other case
 10+ # Invoked with {{GRAMMAR:case|word}}
 11+ /**
 12+ * Cases: rodilnik, dajalnik, tožilnik, mestnik, orodnik
 13+ *
 14+ * @param $word string
 15+ * @param $case string
 16+ *
 17+ * @return string
 18+ */
 19+ function convertGrammar( $word, $case ) {
 20+ global $wgGrammarForms;
 21+ if ( isset( $wgGrammarForms['sl'][$case][$word] ) ) {
 22+ return $wgGrammarForms['sl'][$case][$word];
 23+ }
 24+
 25+ switch ( $case ) {
 26+ case 'mestnik': # locative
 27+ $word = 'o ' . $word; break;
 28+ case 'orodnik': # instrumental
 29+ $word = 'z ' . $word;
 30+ }
 31+
 32+ return $word; # this will return the original value for 'imenovalnik' (nominativ) and all undefined case values
 33+ }
 34+
 35+ /**
 36+ * @param $count int
 37+ * @param $forms array
 38+ *
 39+ * @return string
 40+ */
 41+ function convertPlural( $count, $forms ) {
 42+ if ( !count( $forms ) ) { return ''; }
 43+ $forms = $this->preConvertPlural( $forms, 5 );
 44+
 45+ if ( $count % 100 == 1 ) {
 46+ $index = 0;
 47+ } elseif ( $count % 100 == 2 ) {
 48+ $index = 1;
 49+ } elseif ( $count % 100 == 3 || $count % 100 == 4 ) {
 50+ $index = 2;
 51+ } elseif ( $count != 0 ) {
 52+ $index = 3;
 53+ } else {
 54+ $index = 4;
 55+ }
 56+ return $forms[$index];
 57+ }
 58+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSl.php
___________________________________________________________________
Added: svn:eol-style
159 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageKu.php
@@ -0,0 +1,24 @@
 2+<?php
 3+require_once( dirname( __FILE__ ) . '/../LanguageConverter.php' );
 4+require_once( dirname( __FILE__ ) . '/LanguageKu_ku.php' );
 5+
 6+
 7+/**
 8+ * Kurdish (Kurdî / كوردی)
 9+ *
 10+ * @ingroup Language
 11+ */
 12+class LanguageKu extends LanguageKu_ku {
 13+
 14+ function __construct() {
 15+
 16+ parent::__construct();
 17+
 18+ $variants = array( 'ku', 'ku-arab', 'ku-latn' );
 19+ $variantfallbacks = array(
 20+ 'ku' => 'ku-latn',
 21+ 'ku-arab' => 'ku-latn',
 22+ 'ku-latn' => 'ku-arab',
 23+ );
 24+ }
 25+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageKu.php
___________________________________________________________________
Added: svn:eol-style
126 + native
Index: trunk/tools/ToolserverI18N/language/classes/LanguageSr.php
@@ -0,0 +1,64 @@
 2+<?php
 3+
 4+require_once( dirname( __FILE__ ) . '/../LanguageConverter.php' );
 5+require_once( dirname( __FILE__ ) . '/LanguageSr_ec.php' );
 6+require_once( dirname( __FILE__ ) . '/LanguageSr_el.php' );
 7+
 8+/**
 9+ * Serbian (Српски / Srpski)
 10+ *
 11+ * @ingroup Language
 12+ */
 13+class LanguageSr extends LanguageSr_ec {
 14+ function __construct() {
 15+
 16+
 17+ parent::__construct();
 18+
 19+ $variants = array( 'sr', 'sr-ec', 'sr-el' );
 20+ $variantfallbacks = array(
 21+ 'sr' => 'sr-ec',
 22+ 'sr-ec' => 'sr',
 23+ 'sr-el' => 'sr',
 24+ );
 25+
 26+ $flags = array(
 27+ 'S' => 'S', 'писмо' => 'S', 'pismo' => 'S',
 28+ 'W' => 'W', 'реч' => 'W', 'reč' => 'W', 'ријеч' => 'W', 'riječ' => 'W'
 29+ );
 30+ }
 31+
 32+ /**
 33+ * @param $count int
 34+ * @param $forms array
 35+ *
 36+ * @return string
 37+ */
 38+ function convertPlural( $count, $forms ) {
 39+ if ( !count( $forms ) ) {
 40+ return '';
 41+ }
 42+
 43+ // if no number with word, then use $form[0] for singular and $form[1] for plural or zero
 44+ if ( count( $forms ) === 2 ) {
 45+ return $count == 1 ? $forms[0] : $forms[1];
 46+ }
 47+
 48+ // @todo FIXME: CLDR defines 4 plural forms. Form with decimals missing.
 49+ // See http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ru
 50+ $forms = $this->preConvertPlural( $forms, 3 );
 51+
 52+ if ( $count > 10 && floor( ( $count % 100 ) / 10 ) == 1 ) {
 53+ return $forms[2];
 54+ } else {
 55+ switch ( $count % 10 ) {
 56+ case 1: return $forms[0];
 57+ case 2:
 58+ case 3:
 59+ case 4: return $forms[1];
 60+ default: return $forms[2];
 61+ }
 62+ }
 63+ }
 64+
 65+}
Property changes on: trunk/tools/ToolserverI18N/language/classes/LanguageSr.php
___________________________________________________________________
Added: svn:eol-style
166 + native

Follow-up revisions

RevisionCommit summaryAuthorDate
r91444follow-up r91439: Change option "parse" to "parsemag" (MediaWiki option in th...jan08:30, 5 July 2011
r91589Minor fixes and follow-up to r91439 (Integration of PLURAL / MediaWiki langua...krinkle19:39, 6 July 2011
r102466Readd Names.php and other files removed in r102465...platonides23:35, 8 November 2011

Comments

#Comment by Nikerabbit (talk | contribs)   07:40, 5 July 2011

If you only do plurals when parsing, the mode represents more what MediaWiki calls transform or parsemag.

#Comment by Jan Luca (talk | contribs)   08:31, 5 July 2011

Changed in r91444

#Comment by Krinkle (talk | contribs)   19:40, 6 July 2011

The Language.php is mangled with messed up characters. I suspect you might have copied it from /viewvc/ and/or in a text editor with the wrong encoding set (not UTF-8).

#Comment by Jan Luca (talk | contribs)   20:32, 6 July 2011

I have copied it from my local svn checkout of MW. Maybe I forgot to change the encoding when I edit it to remove MW-specified thing form the constructor but my editors (Notepad++ and Eclipse) normally doesn't change the current encoding of the files.

#Comment by Krinkle (talk | contribs)   23:07, 4 March 2012
Warning: require_once(/home/project/i/n/t/intuition/ToolserverI18N/language/mw-classes/../LanguageConverter.php): failed to open stream: No such file or directory in /home/project/i/n/t/intuition/ToolserverI18N/language/mw-classes/LanguageSr.php on line 3

Fatal error: require_once(): Failed opening required '/home/project/i/n/t/intuition/ToolserverI18N/language/mw-classes/../LanguageConverter.php' (include_path='.:/opt/ts/php/5.3/lib/php') in /home/project/i/n/t/intuition/ToolserverI18N/language/mw-classes/LanguageSr.php on line 3
https://toolserver.org/~intuition/demo/demo8.php?userlang=sr
#Comment by Krinkle (talk | contribs)   22:42, 3 April 2013
#Comment by Siebrand (talk | contribs)   22:52, 3 April 2013

Better late than never :)

Status & tagging log