Index: trunk/tools/ToolserverI18N/TsIntuition.php |
— | — | @@ -82,6 +82,9 @@ |
83 | 83 | |
84 | 84 | // Redirect address and status |
85 | 85 | private $redirectTo = null; |
| 86 | + |
| 87 | + // Object of MessagesFunctions |
| 88 | + private $messagesFunctions = null; |
86 | 89 | |
87 | 90 | /* Init |
88 | 91 | * ------------------------------------------------- */ |
— | — | @@ -328,6 +331,20 @@ |
329 | 332 | return false; |
330 | 333 | } |
331 | 334 | |
| 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 | + } |
332 | 349 | |
333 | 350 | /* Message functions |
334 | 351 | * ------------------------------------------------- */ |
— | — | @@ -342,6 +359,7 @@ |
343 | 360 | * - lang: overrides the currently selected language |
344 | 361 | * - variables: numerical array to do variable replacements ($1> var[0], $2> var[1], etc.) |
345 | 362 | * - 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.) |
346 | 364 | * - escape: Optionally the return can be escaped. By default this takes place after variable |
347 | 365 | * replacement. Set 'raw-variables' to true if you just want the raw message |
348 | 366 | * to be escaped and have escaped the variables already. |
— | — | @@ -364,6 +382,7 @@ |
365 | 383 | 'variables' => array(), |
366 | 384 | 'raw-variables' => false, |
367 | 385 | 'escape' => 'plain', |
| 386 | + 'parse' => false, |
368 | 387 | ); |
369 | 388 | |
370 | 389 | // If $options was a domain string, convert it now. |
— | — | @@ -418,6 +437,11 @@ |
419 | 438 | $n = $i + 1; |
420 | 439 | $msg = str_replace( "\$$n", $val, $msg ); |
421 | 440 | } |
| 441 | + |
| 442 | + // Some parsing work |
| 443 | + if ( $options['parse'] === true ) { |
| 444 | + $msg = $this->getMessagesFunctions()->parse( $msg, $lang ); |
| 445 | + } |
422 | 446 | |
423 | 447 | // If not already escaped, do it now |
424 | 448 | if ( !$escapeDone ) { |
— | — | @@ -816,17 +840,25 @@ |
817 | 841 | * ------------------------------------------------- */ |
818 | 842 | |
819 | 843 | /** |
820 | | - * @TODO: |
| 844 | + * FIXME: Implement in language/MessagesFunctions.php. |
| 845 | + * |
| 846 | + * @todo |
821 | 847 | */ |
822 | 848 | public function gender( $male, $female, $neutral ) { |
823 | 849 | // Depends on getGender() which doesn't exist yet |
| 850 | + throw new BadMethodCallException("Not supported yet!"); |
824 | 851 | } |
825 | 852 | |
826 | 853 | /** |
827 | | - * @TODO: |
| 854 | + * Can be founded in language/MessagesFunctions.php. |
| 855 | + * |
| 856 | + * @see MessagesFunctions::parse |
| 857 | + * @see MessagesFunctions::plural |
| 858 | + * @deprecated |
828 | 859 | */ |
829 | 860 | public function plural( $count, $forms ) { |
830 | | - // Todo |
| 861 | + throw new BadMethodCallException( |
| 862 | + "Use msg() with \"parse\" option to support PLURAL!"); |
831 | 863 | } |
832 | 864 | |
833 | 865 | |
— | — | @@ -1210,7 +1242,7 @@ |
1211 | 1243 | } |
1212 | 1244 | |
1213 | 1245 | // 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 = '' ) { |
1215 | 1247 | $die = false; |
1216 | 1248 | $error = false; |
1217 | 1249 | $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 |
1 | 177 | + 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 |
1 | 72 | + 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 |
1 | 85 | + 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 |
1 | 24 | + 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 |
1 | 10 | + 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 |
1 | 34 | + 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 |
1 | 11 | + 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 |
1 | 25 | + 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 |
1 | 108 | + 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 |
1 | 44 | + 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 |
1 | 24 | + 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 |
1 | 31 | + 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 |
1 | 24 | + 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 |
1 | 34 | + 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 |
1 | 87 | + 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 |
1 | 33 | + 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 |
1 | 184 | + 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 |
1 | 67 | + 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 |
1 | 49 | + 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 |
1 | 32 | + 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 |
1 | 24 | + 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 |
1 | 10 | + 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 |
1 | 56 | + 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 |
1 | 24 | + 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 |
1 | 125 | + 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 |
1 | 347 | + 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 |
1 | 29 | + 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 |
1 | 33 | + 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 |
1 | 25 | + 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 |
1 | 21 | + 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 |
1 | 32 | + 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 |
1 | 11 | + 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 |
1 | 41 | + 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 |
1 | 11 | + 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 |
1 | 110 | + 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 |
1 | 30 | + 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 |
1 | 228 | + 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 |
1 | 24 | + 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 |
1 | 43 | + 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 |
1 | 25 | + 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 |
1 | 24 | + 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 |
1 | 43 | + 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 |
1 | 75 | + 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 |
1 | 148 | + 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 |
1 | 11 | + 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 |
1 | 61 | + 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 |
1 | 148 | + 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 |
1 | 24 | + 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 = '<Conversiontable>'; |
| 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 | + * { and } |
| 1048 | + */ |
| 1049 | + public function armourMath( $text ) { |
| 1050 | + // convert '-{' and '}-' to '-{' and '}-' to prevent |
| 1051 | + // any unwanted markup appearing in the math image tag. |
| 1052 | + $text = strtr( $text, array( '-{' => '-{', '}-' => '}-' ) ); |
| 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( '=>', '=>', $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 |
1 | 1530 | + 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 |
1 | 53 | + 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 |
1 | 54 | + 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 |
1 | 26 | + 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 = "ï¼�123456789ABCDEFGHIJKLï¼ï¼®ï¼¯ï¼°ï¼±ï¼²ï¼³ï¼´ï¼µï¼¶ï¼·ï¼¸ï¼¹ï¼ºï½�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. " ") |
| 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 |
1 | 3529 | + 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 |
1 | 32 | + 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 |
1 | 31 | + 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 |
1 | 96 | + 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 |
1 | 123 | + 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 |
1 | 67 | + 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 |
1 | 48 | + 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 |
1 | 92 | + 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 |
1 | 33 | + 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 |
1 | 744 | + 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 |
1 | 390 | + 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 |
1 | 24 | + 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 |
1 | 47 | + 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 |
1 | 35 | + 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 |
1 | 118 | + 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 |
1 | 36 | + 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 |
1 | 31 | + 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 |
1 | 24 | + 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 |
1 | 63 | + 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 |
1 | 97 | + 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 |
1 | 38 | + 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 |
1 | 32 | + 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 |
1 | 34 | + 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 |
1 | 29 | + 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 |
1 | 59 | + 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 |
1 | 26 | + 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 |
1 | 66 | + native |