6 if( !defined( 'MEDIAWIKI' ) ) {
7 echo "This file is part of MediaWiki, it is not a valid entry point.\n";
12 # In general you should not make customizations in these language files
13 # directly, but should use the MediaWiki: special namespace to customize
14 # user interface messages through the wiki.
15 # See http://meta.wikipedia.org/wiki/MediaWiki_namespace
17 # NOTE TO TRANSLATORS: Do not copy this whole file when making translations!
18 # A lot of common constants and a base class with inheritable methods are
19 # defined here, which should not be redefined. See the other LanguageXx.php
24 global $wgLanguageNames;
25 require_once( dirname(__FILE__
) . '/Names.php' ) ;
27 global $wgInputEncoding, $wgOutputEncoding;
30 * These are always UTF-8, they exist only for backwards compatibility
32 $wgInputEncoding = "UTF-8";
33 $wgOutputEncoding = "UTF-8";
35 if( function_exists( 'mb_strtoupper' ) ) {
36 mb_internal_encoding('UTF-8');
39 /* a fake language converter */
42 function FakeConverter($langobj) {$this->mLang
= $langobj;}
43 function convert($t, $i) {return $t;}
44 function parserConvert($t, $p) {return $t;}
45 function getVariants() { return array( $this->mLang
->getCode() ); }
46 function getPreferredVariant() {return $this->mLang
->getCode(); }
47 function findVariantLink(&$l, &$n) {}
48 function getExtraHashOptions() {return '';}
49 function getParsedTitle() {return '';}
50 function markNoConversion($text, $noParse=false) {return $text;}
51 function convertCategoryKey( $key ) {return $key; }
52 function convertLinkToAllVariants($text){ return array( $this->mLang
->getCode() => $text); }
53 function armourMath($text){ return $text; }
56 #--------------------------------------------------------------------------
57 # Internationalisation code
58 #--------------------------------------------------------------------------
61 var $mConverter, $mVariants, $mCode, $mLoaded = false;
63 static public $mLocalisationKeys = array( 'fallback', 'namespaceNames',
64 'skinNames', 'mathNames',
65 'bookstoreList', 'magicWords', 'messages', 'rtl', 'digitTransformTable',
66 'separatorTransformTable', 'fallback8bitEncoding', 'linkPrefixExtension',
67 'defaultUserOptionOverrides', 'linkTrail', 'namespaceAliases',
68 'dateFormats', 'datePreferences', 'datePreferenceMigrationMap',
69 'defaultDateFormat', 'extraUserToggles', 'specialPageAliases' );
71 static public $mMergeableMapKeys = array( 'messages', 'namespaceNames', 'mathNames',
72 'dateFormats', 'defaultUserOptionOverrides', 'magicWords' );
74 static public $mMergeableListKeys = array( 'extraUserToggles' );
76 static public $mMergeableAliasListKeys = array( 'specialPageAliases' );
78 static public $mLocalisationCache = array();
80 static public $mWeekdayMsgs = array(
81 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
85 static public $mWeekdayAbbrevMsgs = array(
86 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'
89 static public $mMonthMsgs = array(
90 'january', 'february', 'march', 'april', 'may_long', 'june',
91 'july', 'august', 'september', 'october', 'november',
94 static public $mMonthGenMsgs = array(
95 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen',
96 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen',
99 static public $mMonthAbbrevMsgs = array(
100 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug',
101 'sep', 'oct', 'nov', 'dec'
105 * Create a language object for a given language code
107 static function factory( $code ) {
109 static $recursionLevel = 0;
111 if ( $code == 'en' ) {
114 $class = 'Language' . str_replace( '-', '_', ucfirst( $code ) );
115 // Preload base classes to work around APC/PHP5 bug
116 if ( file_exists( "$IP/languages/classes/$class.deps.php" ) ) {
117 include_once("$IP/languages/classes/$class.deps.php");
119 if ( file_exists( "$IP/languages/classes/$class.php" ) ) {
120 include_once("$IP/languages/classes/$class.php");
124 if ( $recursionLevel > 5 ) {
125 throw new MWException( "Language fallback loop detected when creating class $class\n" );
128 if( ! class_exists( $class ) ) {
129 $fallback = Language
::getFallbackFor( $code );
131 $lang = Language
::factory( $fallback );
133 $lang->setCode( $code );
141 function __construct() {
142 $this->mConverter
= new FakeConverter($this);
143 // Set the code to the name of the descendant
144 if ( get_class( $this ) == 'Language' ) {
147 $this->mCode
= str_replace( '_', '-', strtolower( substr( get_class( $this ), 8 ) ) );
152 * Hook which will be called if this is the content language.
153 * Descendants can use this to register hook functions or modify globals
155 function initContLang() {}
161 function getDefaultUserOptions() {
162 return User
::getDefaultOptions();
165 function getFallbackLanguageCode() {
167 return $this->fallback
;
171 * Exports $wgBookstoreListEn
174 function getBookstoreList() {
176 return $this->bookstoreList
;
182 function getNamespaces() {
184 return $this->namespaceNames
;
188 * A convenience function that returns the same thing as
189 * getNamespaces() except with the array values changed to ' '
190 * where it found '_', useful for producing output to be displayed
191 * e.g. in <select> forms.
195 function getFormattedNamespaces() {
196 $ns = $this->getNamespaces();
197 foreach($ns as $k => $v) {
198 $ns[$k] = strtr($v, '_', ' ');
204 * Get a namespace value by key
206 * $mw_ns = $wgContLang->getNsText( NS_MEDIAWIKI );
207 * echo $mw_ns; // prints 'MediaWiki'
210 * @param int $index the array key of the namespace to return
211 * @return mixed, string if the namespace value exists, otherwise false
213 function getNsText( $index ) {
214 $ns = $this->getNamespaces();
215 return isset( $ns[$index] ) ?
$ns[$index] : false;
219 * A convenience function that returns the same thing as
220 * getNsText() except with '_' changed to ' ', useful for
225 function getFormattedNsText( $index ) {
226 $ns = $this->getNsText( $index );
227 return strtr($ns, '_', ' ');
231 * Get a namespace key by value, case insensetive.
233 * @param string $text
234 * @return mixed An integer if $text is a valid value otherwise false
236 function getNsIndex( $text ) {
238 $lctext = $this->lc($text);
239 return isset( $this->mNamespaceIds
[$lctext] ) ?
$this->mNamespaceIds
[$lctext] : false;
243 * short names for language variants used for language conversion links.
245 * @param string $code
248 function getVariantname( $code ) {
249 return $this->getMessageFromDB( "variantname-$code" );
252 function specialPage( $name ) {
253 $aliases = $this->getSpecialPageAliases();
254 if ( isset( $aliases[$name][0] ) ) {
255 $name = $aliases[$name][0];
257 return $this->getNsText(NS_SPECIAL
) . ':' . $name;
260 function getQuickbarSettings() {
262 $this->getMessage( 'qbsettings-none' ),
263 $this->getMessage( 'qbsettings-fixedleft' ),
264 $this->getMessage( 'qbsettings-fixedright' ),
265 $this->getMessage( 'qbsettings-floatingleft' ),
266 $this->getMessage( 'qbsettings-floatingright' )
270 function getSkinNames() {
272 return $this->skinNames
;
275 function getMathNames() {
277 return $this->mathNames
;
280 function getDatePreferences() {
282 return $this->datePreferences
;
285 function getDateFormats() {
287 return $this->dateFormats
;
290 function getDefaultDateFormat() {
292 return $this->defaultDateFormat
;
295 function getDatePreferenceMigrationMap() {
297 return $this->datePreferenceMigrationMap
;
300 function getDefaultUserOptionOverrides() {
302 return $this->defaultUserOptionOverrides
;
305 function getExtraUserToggles() {
307 return $this->extraUserToggles
;
310 function getUserToggle( $tog ) {
311 return $this->getMessageFromDB( "tog-$tog" );
315 * Get language names, indexed by code.
316 * If $customisedOnly is true, only returns codes with a messages file
318 public static function getLanguageNames( $customisedOnly = false ) {
319 global $wgLanguageNames;
320 if ( !$customisedOnly ) {
321 return $wgLanguageNames;
325 $messageFiles = glob( "$IP/languages/messages/Messages*.php" );
327 foreach ( $messageFiles as $file ) {
329 if( preg_match( '/Messages([A-Z][a-z_]+)\.php$/', $file, $m ) ) {
330 $code = str_replace( '_', '-', strtolower( $m[1] ) );
331 if ( isset( $wgLanguageNames[$code] ) ) {
332 $names[$code] = $wgLanguageNames[$code];
340 * Ugly hack to get a message maybe from the MediaWiki namespace, if this
341 * language object is the content or user language.
343 function getMessageFromDB( $msg ) {
344 global $wgContLang, $wgLang;
345 if ( $wgContLang->getCode() == $this->getCode() ) {
347 return wfMsgForContent( $msg );
348 } elseif ( $wgLang->getCode() == $this->getCode() ) {
350 return wfMsg( $msg );
352 # Neither, get from localisation
353 return $this->getMessage( $msg );
357 function getLanguageName( $code ) {
358 global $wgLanguageNames;
359 if ( ! array_key_exists( $code, $wgLanguageNames ) ) {
362 return $wgLanguageNames[$code];
365 function getMonthName( $key ) {
366 return $this->getMessageFromDB( self
::$mMonthMsgs[$key-1] );
369 function getMonthNameGen( $key ) {
370 return $this->getMessageFromDB( self
::$mMonthGenMsgs[$key-1] );
373 function getMonthAbbreviation( $key ) {
374 return $this->getMessageFromDB( self
::$mMonthAbbrevMsgs[$key-1] );
377 function getWeekdayName( $key ) {
378 return $this->getMessageFromDB( self
::$mWeekdayMsgs[$key-1] );
381 function getWeekdayAbbreviation( $key ) {
382 return $this->getMessageFromDB( self
::$mWeekdayAbbrevMsgs[$key-1] );
386 * Used by date() and time() to adjust the time output.
388 * @param int $ts the time in date('YmdHis') format
389 * @param mixed $tz adjust the time by this amount (default false,
390 * mean we get user timecorrection setting)
393 function userAdjust( $ts, $tz = false ) {
394 global $wgUser, $wgLocalTZoffset;
397 $tz = $wgUser->getOption( 'timecorrection' );
400 # minutes and hours differences:
405 # Global offset in minutes.
406 if( isset($wgLocalTZoffset) ) {
407 $hrDiff = $wgLocalTZoffset %
60;
408 $minDiff = $wgLocalTZoffset - ($hrDiff * 60);
410 } elseif ( strpos( $tz, ':' ) !== false ) {
411 $tzArray = explode( ':', $tz );
412 $hrDiff = intval($tzArray[0]);
413 $minDiff = intval($hrDiff < 0 ?
-$tzArray[1] : $tzArray[1]);
415 $hrDiff = intval( $tz );
418 # No difference ? Return time unchanged
419 if ( 0 == $hrDiff && 0 == $minDiff ) { return $ts; }
421 # Generate an adjusted date
423 (int)substr( $ts, 8, 2) ) +
$hrDiff, # Hours
424 (int)substr( $ts, 10, 2 ) +
$minDiff, # Minutes
425 (int)substr( $ts, 12, 2 ), # Seconds
426 (int)substr( $ts, 4, 2 ), # Month
427 (int)substr( $ts, 6, 2 ), # Day
428 (int)substr( $ts, 0, 4 ) ); #Year
429 return date( 'YmdHis', $t );
433 * This is a workalike of PHP's date() function, but with better
434 * internationalisation, a reduced set of format characters, and a better
437 * Supported format characters are dDjlNwzWFmMntLYyaAgGhHiscrU. See the
438 * PHP manual for definitions. There are a number of extensions, which
441 * xn Do not translate digits of the next numeric format character
442 * xN Toggle raw digit (xn) flag, stays set until explicitly unset
443 * xr Use roman numerals for the next numeric format character
445 * xg Genitive month name
447 * Characters enclosed in double quotes will be considered literal (with
448 * the quotes themselves removed). Unmatched quotes will be considered
449 * literal quotes. Example:
451 * "The month is" F => The month is January
454 * Backslash escaping is also supported.
456 * @param string $format
457 * @param string $ts 14-character timestamp
461 function sprintfDate( $format, $ts ) {
467 for ( $p = 0; $p < strlen( $format ); $p++
) {
470 if ( $code == 'x' && $p < strlen( $format ) - 1 ) {
471 $code .= $format[++
$p];
482 $rawToggle = !$rawToggle;
488 $s .= $this->getMonthNameGen( substr( $ts, 4, 2 ) );
491 $num = substr( $ts, 6, 2 );
494 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
495 $s .= $this->getWeekdayAbbreviation( date( 'w', $unix ) +
1 );
498 $num = intval( substr( $ts, 6, 2 ) );
501 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
502 $s .= $this->getWeekdayName( date( 'w', $unix ) +
1 );
505 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
506 $w = date( 'w', $unix );
510 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
511 $num = date( 'w', $unix );
514 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
515 $num = date( 'z', $unix );
518 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
519 $num = date( 'W', $unix );
522 $s .= $this->getMonthName( substr( $ts, 4, 2 ) );
525 $num = substr( $ts, 4, 2 );
528 $s .= $this->getMonthAbbreviation( substr( $ts, 4, 2 ) );
531 $num = intval( substr( $ts, 4, 2 ) );
534 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
535 $num = date( 't', $unix );
538 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
539 $num = date( 'L', $unix );
542 $num = substr( $ts, 0, 4 );
545 $num = substr( $ts, 2, 2 );
548 $s .= intval( substr( $ts, 8, 2 ) ) < 12 ?
'am' : 'pm';
551 $s .= intval( substr( $ts, 8, 2 ) ) < 12 ?
'AM' : 'PM';
554 $h = substr( $ts, 8, 2 );
555 $num = $h %
12 ?
$h %
12 : 12;
558 $num = intval( substr( $ts, 8, 2 ) );
561 $h = substr( $ts, 8, 2 );
562 $num = sprintf( '%02d', $h %
12 ?
$h %
12 : 12 );
565 $num = substr( $ts, 8, 2 );
568 $num = substr( $ts, 10, 2 );
571 $num = substr( $ts, 12, 2 );
574 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
575 $s .= date( 'c', $unix );
578 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
579 $s .= date( 'r', $unix );
582 if ( !$unix ) $unix = wfTimestamp( TS_UNIX
, $ts );
587 if ( $p < strlen( $format ) - 1 ) {
595 if ( $p < strlen( $format ) - 1 ) {
596 $endQuote = strpos( $format, '"', $p +
1 );
597 if ( $endQuote === false ) {
598 # No terminating quote, assume literal "
601 $s .= substr( $format, $p +
1, $endQuote - $p - 1 );
605 # Quote at end of string, assume literal "
612 if ( $num !== false ) {
613 if ( $rawToggle ||
$raw ) {
616 } elseif ( $roman ) {
617 $s .= self
::romanNumeral( $num );
620 $s .= $this->formatNum( $num, true );
629 * Roman number formatting up to 3000
631 static function romanNumeral( $num ) {
632 static $table = array(
633 array( '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X' ),
634 array( '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', 'C' ),
635 array( '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', 'M' ),
636 array( '', 'M', 'MM', 'MMM' )
639 $num = intval( $num );
640 if ( $num > 3000 ||
$num <= 0 ) {
645 for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
646 if ( $num >= $pow10 ) {
647 $s .= $table[$i][floor($num / $pow10)];
649 $num = $num %
$pow10;
655 * This is meant to be used by time(), date(), and timeanddate() to get
656 * the date preference they're supposed to use, it should be used in
660 * function timeanddate([...], $format = true) {
661 * $datePreference = $this->dateFormat($format);
666 * @param mixed $usePrefs: if true, the user's preference is used
667 * if false, the site/language default is used
668 * if int/string, assumed to be a format.
671 function dateFormat( $usePrefs = true ) {
674 if( is_bool( $usePrefs ) ) {
676 $datePreference = $wgUser->getDatePreference();
678 $options = User
::getDefaultOptions();
679 $datePreference = (string)$options['date'];
682 $datePreference = (string)$usePrefs;
686 if( $datePreference == '' ) {
690 return $datePreference;
695 * @param mixed $ts the time format which needs to be turned into a
696 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
697 * @param bool $adj whether to adjust the time output according to the
698 * user configured offset ($timecorrection)
699 * @param mixed $format true to use user's date format preference
700 * @param string $timecorrection the time offset as returned by
701 * validateTimeZone() in Special:Preferences
704 function date( $ts, $adj = false, $format = true, $timecorrection = false ) {
707 $ts = $this->userAdjust( $ts, $timecorrection );
710 $pref = $this->dateFormat( $format );
711 if( $pref == 'default' ||
!isset( $this->dateFormats
["$pref date"] ) ) {
712 $pref = $this->defaultDateFormat
;
714 return $this->sprintfDate( $this->dateFormats
["$pref date"], $ts );
719 * @param mixed $ts the time format which needs to be turned into a
720 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
721 * @param bool $adj whether to adjust the time output according to the
722 * user configured offset ($timecorrection)
723 * @param mixed $format true to use user's date format preference
724 * @param string $timecorrection the time offset as returned by
725 * validateTimeZone() in Special:Preferences
728 function time( $ts, $adj = false, $format = true, $timecorrection = false ) {
731 $ts = $this->userAdjust( $ts, $timecorrection );
734 $pref = $this->dateFormat( $format );
735 if( $pref == 'default' ||
!isset( $this->dateFormats
["$pref time"] ) ) {
736 $pref = $this->defaultDateFormat
;
738 return $this->sprintfDate( $this->dateFormats
["$pref time"], $ts );
743 * @param mixed $ts the time format which needs to be turned into a
744 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
745 * @param bool $adj whether to adjust the time output according to the
746 * user configured offset ($timecorrection)
748 * @param mixed $format what format to return, if it's false output the
749 * default one (default true)
750 * @param string $timecorrection the time offset as returned by
751 * validateTimeZone() in Special:Preferences
754 function timeanddate( $ts, $adj = false, $format = true, $timecorrection = false) {
757 ## Account for non-integer timestamps
758 if (substr($ts,4,1) === '-') {
759 $ts = preg_replace('/\D/', '', $ts);
763 $ts = $this->userAdjust( $ts, $timecorrection );
766 $pref = $this->dateFormat( $format );
767 if( $pref == 'default' ||
!isset( $this->dateFormats
["$pref both"] ) ) {
768 $pref = $this->defaultDateFormat
;
771 return $this->sprintfDate( $this->dateFormats
["$pref both"], $ts );
774 function getMessage( $key ) {
776 return isset( $this->messages
[$key] ) ?
$this->messages
[$key] : null;
779 function getAllMessages() {
781 return $this->messages
;
784 function iconv( $in, $out, $string ) {
785 # For most languages, this is a wrapper for iconv
786 return iconv( $in, $out . '//IGNORE', $string );
789 // callback functions for uc(), lc(), ucwords(), ucwordbreaks()
790 function ucwordbreaksCallbackAscii($matches){
791 return $this->ucfirst($matches[1]);
794 function ucwordbreaksCallbackMB($matches){
795 return mb_strtoupper($matches[0]);
798 function ucCallback($matches){
799 list( $wikiUpperChars ) = self
::getCaseMaps();
800 return strtr( $matches[1], $wikiUpperChars );
803 function lcCallback($matches){
804 list( , $wikiLowerChars ) = self
::getCaseMaps();
805 return strtr( $matches[1], $wikiLowerChars );
808 function ucwordsCallbackMB($matches){
809 return mb_strtoupper($matches[0]);
812 function ucwordsCallbackWiki($matches){
813 list( $wikiUpperChars ) = self
::getCaseMaps();
814 return strtr( $matches[0], $wikiUpperChars );
817 function ucfirst( $str ) {
818 return self
::uc( $str, true );
821 function uc( $str, $first = false ) {
822 if ( function_exists( 'mb_strtoupper' ) ) {
824 if ( self
::isMultibyte( $str ) ) {
825 return mb_strtoupper( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
827 return ucfirst( $str );
830 return self
::isMultibyte( $str ) ?
mb_strtoupper( $str ) : strtoupper( $str );
833 if ( self
::isMultibyte( $str ) ) {
834 list( $wikiUpperChars ) = $this->getCaseMaps();
835 $x = $first ?
'^' : '';
836 return preg_replace_callback(
837 "/$x([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/",
838 array($this,"ucCallback"),
842 return $first ?
ucfirst( $str ) : strtoupper( $str );
847 function lcfirst( $str ) {
848 return self
::lc( $str, true );
851 function lc( $str, $first = false ) {
852 if ( function_exists( 'mb_strtolower' ) )
854 if ( self
::isMultibyte( $str ) )
855 return mb_strtolower( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
857 return strtolower( substr( $str, 0, 1 ) ) . substr( $str, 1 );
859 return self
::isMultibyte( $str ) ?
mb_strtolower( $str ) : strtolower( $str );
861 if ( self
::isMultibyte( $str ) ) {
862 list( , $wikiLowerChars ) = self
::getCaseMaps();
863 $x = $first ?
'^' : '';
864 return preg_replace_callback(
865 "/$x([A-Z]|[\\xc0-\\xff][\\x80-\\xbf]*)/",
866 array($this,"lcCallback"),
870 return $first ?
strtolower( substr( $str, 0, 1 ) ) . substr( $str, 1 ) : strtolower( $str );
873 function isMultibyte( $str ) {
874 return (bool)preg_match( '/[\x80-\xff]/', $str );
877 function ucwords($str) {
878 if ( self
::isMultibyte( $str ) ) {
879 $str = self
::lc($str);
881 // regexp to find first letter in each word (i.e. after each space)
882 $replaceRegexp = "/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)| ([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/";
884 // function to use to capitalize a single char
885 if ( function_exists( 'mb_strtoupper' ) )
886 return preg_replace_callback(
888 array($this,"ucwordsCallbackMB"),
892 return preg_replace_callback(
894 array($this,"ucwordsCallbackWiki"),
899 return ucwords( strtolower( $str ) );
902 # capitalize words at word breaks
903 function ucwordbreaks($str){
904 if (self
::isMultibyte( $str ) ) {
905 $str = self
::lc($str);
907 // since \b doesn't work for UTF-8, we explicitely define word break chars
908 $breaks= "[ \-\(\)\}\{\.,\?!]";
910 // find first letter after word break
911 $replaceRegexp = "/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)|$breaks([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/";
913 if ( function_exists( 'mb_strtoupper' ) )
914 return preg_replace_callback(
916 array($this,"ucwordbreaksCallbackMB"),
920 return preg_replace_callback(
922 array($this,"ucwordsCallbackWiki"),
927 return preg_replace_callback(
928 '/\b([\w\x80-\xff]+)\b/',
929 array($this,"ucwordbreaksCallbackAscii"),
934 * Return a case-folded representation of $s
936 * This is a representation such that caseFold($s1)==caseFold($s2) if $s1
937 * and $s2 are the same except for the case of their characters. It is not
938 * necessary for the value returned to make sense when displayed.
940 * Do *not* perform any other normalisation in this function. If a caller
941 * uses this function when it should be using a more general normalisation
942 * function, then fix the caller.
944 function caseFold( $s ) {
945 return $this->uc( $s );
948 function checkTitleEncoding( $s ) {
949 if( is_array( $s ) ) {
950 wfDebugDieBacktrace( 'Given array to checkTitleEncoding.' );
952 # Check for non-UTF-8 URLs
953 $ishigh = preg_match( '/[\x80-\xff]/', $s);
954 if(!$ishigh) return $s;
956 $isutf8 = preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
957 '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
958 if( $isutf8 ) return $s;
960 return $this->iconv( $this->fallback8bitEncoding(), "utf-8", $s );
963 function fallback8bitEncoding() {
965 return $this->fallback8bitEncoding
;
969 * Some languages have special punctuation to strip out
970 * or characters which need to be converted for MySQL's
971 * indexing to grok it correctly. Make such changes here.
976 function stripForSearch( $string ) {
978 if ( $wgDBtype != 'mysql' ) {
982 # MySQL fulltext index doesn't grok utf-8, so we
983 # need to fold cases and convert to hex
985 wfProfileIn( __METHOD__
);
986 if( function_exists( 'mb_strtolower' ) ) {
988 "/([\\xc0-\\xff][\\x80-\\xbf]*)/e",
989 "'U8' . bin2hex( \"$1\" )",
990 mb_strtolower( $string ) );
992 list( , $wikiLowerChars ) = self
::getCaseMaps();
994 "/([\\xc0-\\xff][\\x80-\\xbf]*)/e",
995 "'U8' . bin2hex( strtr( \"\$1\", \$wikiLowerChars ) )",
998 wfProfileOut( __METHOD__
);
1002 function convertForSearchResult( $termsArray ) {
1003 # some languages, e.g. Chinese, need to do a conversion
1004 # in order for search results to be displayed correctly
1009 * Get the first character of a string.
1014 function firstChar( $s ) {
1016 preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
1017 '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})/', $s, $matches);
1019 return isset( $matches[1] ) ?
$matches[1] : "";
1022 function initEncoding() {
1023 # Some languages may have an alternate char encoding option
1024 # (Esperanto X-coding, Japanese furigana conversion, etc)
1025 # If this language is used as the primary content language,
1026 # an override to the defaults can be set here on startup.
1029 function recodeForEdit( $s ) {
1030 # For some languages we'll want to explicitly specify
1031 # which characters make it into the edit box raw
1032 # or are converted in some way or another.
1033 # Note that if wgOutputEncoding is different from
1034 # wgInputEncoding, this text will be further converted
1035 # to wgOutputEncoding.
1036 global $wgEditEncoding;
1037 if( $wgEditEncoding == '' or
1038 $wgEditEncoding == 'UTF-8' ) {
1041 return $this->iconv( 'UTF-8', $wgEditEncoding, $s );
1045 function recodeInput( $s ) {
1046 # Take the previous into account.
1047 global $wgEditEncoding;
1048 if($wgEditEncoding != "") {
1049 $enc = $wgEditEncoding;
1053 if( $enc == 'UTF-8' ) {
1056 return $this->iconv( $enc, 'UTF-8', $s );
1061 * For right-to-left language support
1071 * A hidden direction mark (LRM or RLM), depending on the language direction
1075 function getDirMark() {
1076 return $this->isRTL() ?
"\xE2\x80\x8F" : "\xE2\x80\x8E";
1080 * An arrow, depending on the language direction
1084 function getArrow() {
1085 return $this->isRTL() ?
'←' : '→';
1089 * To allow "foo[[bar]]" to extend the link over the whole word "foobar"
1093 function linkPrefixExtension() {
1095 return $this->linkPrefixExtension
;
1098 function &getMagicWords() {
1100 return $this->magicWords
;
1103 # Fill a MagicWord object with data from here
1104 function getMagic( &$mw ) {
1105 if ( !isset( $this->mMagicExtensions
) ) {
1106 $this->mMagicExtensions
= array();
1107 wfRunHooks( 'LanguageGetMagic', array( &$this->mMagicExtensions
, $this->getCode() ) );
1109 if ( isset( $this->mMagicExtensions
[$mw->mId
] ) ) {
1110 $rawEntry = $this->mMagicExtensions
[$mw->mId
];
1112 $magicWords =& $this->getMagicWords();
1113 if ( isset( $magicWords[$mw->mId
] ) ) {
1114 $rawEntry = $magicWords[$mw->mId
];
1116 # Fall back to English if local list is incomplete
1117 $magicWords =& Language
::getMagicWords();
1118 $rawEntry = $magicWords[$mw->mId
];
1122 if( !is_array( $rawEntry ) ) {
1123 error_log( "\"$rawEntry\" is not a valid magic thingie for \"$mw->mId\"" );
1125 $mw->mCaseSensitive
= $rawEntry[0];
1126 $mw->mSynonyms
= array_slice( $rawEntry, 1 );
1130 * Get special page names, as an associative array
1131 * case folded alias => real name
1133 function getSpecialPageAliases() {
1135 if ( !isset( $this->mExtendedSpecialPageAliases
) ) {
1136 $this->mExtendedSpecialPageAliases
= $this->specialPageAliases
;
1137 wfRunHooks( 'LangugeGetSpecialPageAliases',
1138 array( &$this->mExtendedSpecialPageAliases
, $this->getCode() ) );
1140 return $this->mExtendedSpecialPageAliases
;
1144 * Italic is unsuitable for some languages
1148 * @param string $text The text to be emphasized.
1151 function emphasize( $text ) {
1152 return "<em>$text</em>";
1156 * Normally we output all numbers in plain en_US style, that is
1157 * 293,291.235 for twohundredninetythreethousand-twohundredninetyone
1158 * point twohundredthirtyfive. However this is not sutable for all
1159 * languages, some such as Pakaran want ੨੯੩,੨੯੫.੨੩੫ and others such as
1160 * Icelandic just want to use commas instead of dots, and dots instead
1161 * of commas like "293.291,235".
1163 * An example of this function being called:
1165 * wfMsg( 'message', $wgLang->formatNum( $num ) )
1168 * See LanguageGu.php for the Gujarati implementation and
1169 * LanguageIs.php for the , => . and . => , implementation.
1171 * @todo check if it's viable to use localeconv() for the decimal
1174 * @param mixed $number the string to be formatted, should be an integer or
1175 * a floating point number.
1176 * @param bool $nocommafy Set to true for special numbers like dates
1179 function formatNum( $number, $nocommafy = false ) {
1180 global $wgTranslateNumerals;
1182 $number = $this->commafy($number);
1183 $s = $this->separatorTransformTable();
1184 if (!is_null($s)) { $number = strtr($number, $s); }
1187 if ($wgTranslateNumerals) {
1188 $s = $this->digitTransformTable();
1189 if (!is_null($s)) { $number = strtr($number, $s); }
1195 function parseFormattedNumber( $number ) {
1196 $s = $this->digitTransformTable();
1197 if (!is_null($s)) { $number = strtr($number, array_flip($s)); }
1199 $s = $this->separatorTransformTable();
1200 if (!is_null($s)) { $number = strtr($number, array_flip($s)); }
1202 $number = strtr( $number, array (',' => '') );
1207 * Adds commas to a given number
1212 function commafy($_) {
1213 return strrev((string)preg_replace('/(\d{3})(?=\d)(?!\d*\.)/','$1,',strrev($_)));
1216 function digitTransformTable() {
1218 return $this->digitTransformTable
;
1221 function separatorTransformTable() {
1223 return $this->separatorTransformTable
;
1228 * For the credit list in includes/Credits.php (action=credits)
1233 function listToText( $l ) {
1236 for ($i = $m; $i >= 0; $i--) {
1239 } else if ($i == $m - 1) {
1240 $s = $l[$i] . ' ' . $this->getMessageFromDB( 'and' ) . ' ' . $s;
1242 $s = $l[$i] . ', ' . $s;
1248 # Crop a string from the beginning or end to a certain number of bytes.
1249 # (Bytes are used because our storage has limited byte lengths for some
1250 # columns in the database.) Multibyte charsets will need to make sure that
1251 # only whole characters are included!
1253 # $length does not include the optional ellipsis.
1254 # If $length is negative, snip from the beginning
1255 function truncate( $string, $length, $ellipsis = "" ) {
1256 if( $length == 0 ) {
1259 if ( strlen( $string ) <= abs( $length ) ) {
1263 $string = substr( $string, 0, $length );
1264 $char = ord( $string[strlen( $string ) - 1] );
1266 if ($char >= 0xc0) {
1267 # We got the first byte only of a multibyte char; remove it.
1268 $string = substr( $string, 0, -1 );
1269 } elseif( $char >= 0x80 &&
1270 preg_match( '/^(.*)(?:[\xe0-\xef][\x80-\xbf]|' .
1271 '[\xf0-\xf7][\x80-\xbf]{1,2})$/', $string, $m ) ) {
1272 # We chopped in the middle of a character; remove it
1275 return $string . $ellipsis;
1277 $string = substr( $string, $length );
1278 $char = ord( $string[0] );
1279 if( $char >= 0x80 && $char < 0xc0 ) {
1280 # We chopped in the middle of a character; remove the whole thing
1281 $string = preg_replace( '/^[\x80-\xbf]+/', '', $string );
1283 return $ellipsis . $string;
1288 * Grammatical transformations, needed for inflected languages
1289 * Invoked by putting {{grammar:case|word}} in a message
1291 * @param string $word
1292 * @param string $case
1295 function convertGrammar( $word, $case ) {
1296 global $wgGrammarForms;
1297 if ( isset($wgGrammarForms['en'][$case][$word]) ) {
1298 return $wgGrammarForms['en'][$case][$word];
1304 * Plural form transformations, needed for some languages.
1305 * For example, where are 3 form of plural in Russian and Polish,
1306 * depending on "count mod 10". See [[w:Plural]]
1307 * For English it is pretty simple.
1309 * Invoked by putting {{plural:count|wordform1|wordform2}}
1310 * or {{plural:count|wordform1|wordform2|wordform3}}
1312 * Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}}
1314 * @param integer $count
1315 * @param string $wordform1
1316 * @param string $wordform2
1317 * @param string $wordform3 (optional)
1318 * @param string $wordform4 (optional)
1319 * @param string $wordform5 (optional)
1322 function convertPlural( $count, $w1, $w2, $w3, $w4, $w5) {
1323 return ( $count == '1' ||
$count == '-1' ) ?
$w1 : $w2;
1327 * For translaing of expiry times
1328 * @param string The validated block time in English
1329 * @param $forContent, avoid html?
1330 * @return Somehow translated block time
1331 * @see LanguageFi.php for example implementation
1333 function translateBlockExpiry( $str, $forContent=false ) {
1335 $scBlockExpiryOptions = $this->getMessageFromDB( 'ipboptions' );
1337 if ( $scBlockExpiryOptions == '-') {
1341 foreach (explode(',', $scBlockExpiryOptions) as $option) {
1342 if ( strpos($option, ":") === false )
1344 list($show, $value) = explode(":", $option);
1345 if ( strcmp ( $str, $value) == 0 ) {
1347 return htmlspecialchars($str) . htmlspecialchars( trim( $show ) );
1349 return '<span title="' . htmlspecialchars($str). '">' . htmlspecialchars( trim( $show ) ) . '</span>';
1357 * languages like Chinese need to be segmented in order for the diff
1360 * @param string $text
1363 function segmentForDiff( $text ) {
1368 * and unsegment to show the result
1370 * @param string $text
1373 function unsegmentForDiff( $text ) {
1377 # convert text to different variants of a language.
1378 function convert( $text, $isTitle = false) {
1379 return $this->mConverter
->convert($text, $isTitle);
1382 # Convert text from within Parser
1383 function parserConvert( $text, &$parser ) {
1384 return $this->mConverter
->parserConvert( $text, $parser );
1387 # Check if this is a language with variants
1388 function hasVariants(){
1389 return sizeof($this->getVariants())>1;
1392 # Put custom tags (e.g. -{ }-) around math to prevent conversion
1393 function armourMath($text){
1394 return $this->mConverter
->armourMath($text);
1399 * Perform output conversion on a string, and encode for safe HTML output.
1400 * @param string $text
1401 * @param bool $isTitle -- wtf?
1403 * @todo this should get integrated somewhere sane
1405 function convertHtml( $text, $isTitle = false ) {
1406 return htmlspecialchars( $this->convert( $text, $isTitle ) );
1409 function convertCategoryKey( $key ) {
1410 return $this->mConverter
->convertCategoryKey( $key );
1414 * get the list of variants supported by this langauge
1415 * see sample implementation in LanguageZh.php
1417 * @return array an array of language codes
1419 function getVariants() {
1420 return $this->mConverter
->getVariants();
1424 function getPreferredVariant( $fromUser = true ) {
1425 return $this->mConverter
->getPreferredVariant( $fromUser );
1429 * if a language supports multiple variants, it is
1430 * possible that non-existing link in one variant
1431 * actually exists in another variant. this function
1432 * tries to find it. See e.g. LanguageZh.php
1434 * @param string $link the name of the link
1435 * @param mixed $nt the title object of the link
1436 * @return null the input parameters may be modified upon return
1438 function findVariantLink( &$link, &$nt ) {
1439 $this->mConverter
->findVariantLink($link, $nt);
1443 * If a language supports multiple variants, converts text
1444 * into an array of all possible variants of the text:
1445 * 'variant' => text in that variant
1448 function convertLinkToAllVariants($text){
1449 return $this->mConverter
->convertLinkToAllVariants($text);
1454 * returns language specific options used by User::getPageRenderHash()
1455 * for example, the preferred language variant
1460 function getExtraHashOptions() {
1461 return $this->mConverter
->getExtraHashOptions();
1465 * for languages that support multiple variants, the title of an
1466 * article may be displayed differently in different variants. this
1467 * function returns the apporiate title defined in the body of the article.
1471 function getParsedTitle() {
1472 return $this->mConverter
->getParsedTitle();
1476 * Enclose a string with the "no conversion" tag. This is used by
1477 * various functions in the Parser
1479 * @param string $text text to be tagged for no conversion
1480 * @return string the tagged text
1482 function markNoConversion( $text, $noParse=false ) {
1483 return $this->mConverter
->markNoConversion( $text, $noParse );
1487 * A regular expression to match legal word-trailing characters
1488 * which should be merged onto a link of the form [[foo]]bar.
1493 function linkTrail() {
1495 return $this->linkTrail
;
1498 function getLangObj() {
1503 * Get the RFC 3066 code for this language object
1505 function getCode() {
1506 return $this->mCode
;
1509 function setCode( $code ) {
1510 $this->mCode
= $code;
1513 static function getFileName( $prefix = 'Language', $code, $suffix = '.php' ) {
1514 return $prefix . str_replace( '-', '_', ucfirst( $code ) ) . $suffix;
1517 static function getMessagesFileName( $code ) {
1519 return self
::getFileName( "$IP/languages/messages/Messages", $code, '.php' );
1522 static function getClassFileName( $code ) {
1524 return self
::getFileName( "$IP/languages/classes/Language", $code, '.php' );
1527 static function getLocalisationArray( $code, $disableCache = false ) {
1528 self
::loadLocalisation( $code, $disableCache );
1529 return self
::$mLocalisationCache[$code];
1533 * Load localisation data for a given code into the static cache
1535 * @return array Dependencies, map of filenames to mtimes
1537 static function loadLocalisation( $code, $disableCache = false ) {
1538 static $recursionGuard = array();
1542 throw new MWException( "Invalid language code requested" );
1545 if ( !$disableCache ) {
1546 # Try the per-process cache
1547 if ( isset( self
::$mLocalisationCache[$code] ) ) {
1548 return self
::$mLocalisationCache[$code]['deps'];
1551 wfProfileIn( __METHOD__
);
1553 # Try the serialized directory
1554 $cache = wfGetPrecompiledData( self
::getFileName( "Messages", $code, '.ser' ) );
1556 self
::$mLocalisationCache[$code] = $cache;
1557 wfDebug( "Language::loadLocalisation(): got localisation for $code from precompiled data file\n" );
1558 wfProfileOut( __METHOD__
);
1559 return self
::$mLocalisationCache[$code]['deps'];
1562 # Try the global cache
1563 $memcKey = wfMemcKey('localisation', $code );
1564 $cache = $wgMemc->get( $memcKey );
1566 # Check file modification times
1567 foreach ( $cache['deps'] as $file => $mtime ) {
1568 if ( !file_exists( $file ) ||
filemtime( $file ) > $mtime ) {
1572 if ( self
::isLocalisationOutOfDate( $cache ) ) {
1573 $wgMemc->delete( $memcKey );
1575 wfDebug( "Language::loadLocalisation(): localisation cache for $code had expired due to update of $file\n" );
1577 self
::$mLocalisationCache[$code] = $cache;
1578 wfDebug( "Language::loadLocalisation(): got localisation for $code from cache\n" );
1579 wfProfileOut( __METHOD__
);
1580 return $cache['deps'];
1584 wfProfileIn( __METHOD__
);
1587 # Default fallback, may be overridden when the messages file is included
1588 if ( $code != 'en' ) {
1594 # Load the primary localisation from the source file
1595 $filename = self
::getMessagesFileName( $code );
1596 if ( !file_exists( $filename ) ) {
1597 wfDebug( "Language::loadLocalisation(): no localisation file for $code, using implicit fallback to en\n" );
1601 $deps = array( $filename => filemtime( $filename ) );
1602 require( $filename );
1603 $cache = compact( self
::$mLocalisationKeys );
1604 wfDebug( "Language::loadLocalisation(): got localisation for $code from source\n" );
1607 if ( !empty( $fallback ) ) {
1608 # Load the fallback localisation, with a circular reference guard
1609 if ( isset( $recursionGuard[$code] ) ) {
1610 throw new MWException( "Error: Circular fallback reference in language code $code" );
1612 $recursionGuard[$code] = true;
1613 $newDeps = self
::loadLocalisation( $fallback, $disableCache );
1614 unset( $recursionGuard[$code] );
1616 $secondary = self
::$mLocalisationCache[$fallback];
1617 $deps = array_merge( $deps, $newDeps );
1619 # Merge the fallback localisation with the current localisation
1620 foreach ( self
::$mLocalisationKeys as $key ) {
1621 if ( isset( $cache[$key] ) ) {
1622 if ( isset( $secondary[$key] ) ) {
1623 if ( in_array( $key, self
::$mMergeableMapKeys ) ) {
1624 $cache[$key] = $cache[$key] +
$secondary[$key];
1625 } elseif ( in_array( $key, self
::$mMergeableListKeys ) ) {
1626 $cache[$key] = array_merge( $secondary[$key], $cache[$key] );
1627 } elseif ( in_array( $key, self
::$mMergeableAliasListKeys ) ) {
1628 $cache[$key] = array_merge_recursive( $cache[$key], $secondary[$key] );
1632 $cache[$key] = $secondary[$key];
1636 # Merge bookstore lists if requested
1637 if ( !empty( $cache['bookstoreList']['inherit'] ) ) {
1638 $cache['bookstoreList'] = array_merge( $cache['bookstoreList'], $secondary['bookstoreList'] );
1640 if ( isset( $cache['bookstoreList']['inherit'] ) ) {
1641 unset( $cache['bookstoreList']['inherit'] );
1645 # Add dependencies to the cache entry
1646 $cache['deps'] = $deps;
1648 # Replace spaces with underscores in namespace names
1649 $cache['namespaceNames'] = str_replace( ' ', '_', $cache['namespaceNames'] );
1651 # Save to both caches
1652 self
::$mLocalisationCache[$code] = $cache;
1653 if ( !$disableCache ) {
1654 $wgMemc->set( $memcKey, $cache );
1657 wfProfileOut( __METHOD__
);
1662 * Test if a given localisation cache is out of date with respect to the
1663 * source Messages files. This is done automatically for the global cache
1664 * in $wgMemc, but is only done on certain occasions for the serialized
1667 * @param $cache mixed Either a language code or a cache array
1669 static function isLocalisationOutOfDate( $cache ) {
1670 if ( !is_array( $cache ) ) {
1671 self
::loadLocalisation( $cache );
1672 $cache = self
::$mLocalisationCache[$cache];
1675 foreach ( $cache['deps'] as $file => $mtime ) {
1676 if ( !file_exists( $file ) ||
filemtime( $file ) > $mtime ) {
1685 * Get the fallback for a given language
1687 static function getFallbackFor( $code ) {
1688 self
::loadLocalisation( $code );
1689 return self
::$mLocalisationCache[$code]['fallback'];
1693 * Get all messages for a given language
1695 static function getMessagesFor( $code ) {
1696 self
::loadLocalisation( $code );
1697 return self
::$mLocalisationCache[$code]['messages'];
1701 * Get a message for a given language
1703 static function getMessageFor( $key, $code ) {
1704 self
::loadLocalisation( $code );
1705 return isset( self
::$mLocalisationCache[$code]['messages'][$key] ) ? self
::$mLocalisationCache[$code]['messages'][$key] : null;
1709 * Load localisation data for this object
1712 if ( !$this->mLoaded
) {
1713 self
::loadLocalisation( $this->getCode() );
1714 $cache =& self
::$mLocalisationCache[$this->getCode()];
1715 foreach ( self
::$mLocalisationKeys as $key ) {
1716 $this->$key = $cache[$key];
1718 $this->mLoaded
= true;
1720 $this->fixUpSettings();
1725 * Do any necessary post-cache-load settings adjustment
1727 function fixUpSettings() {
1728 global $wgExtraNamespaces, $wgMetaNamespace, $wgMetaNamespaceTalk,
1729 $wgNamespaceAliases, $wgAmericanDates;
1730 wfProfileIn( __METHOD__
);
1731 if ( $wgExtraNamespaces ) {
1732 $this->namespaceNames
= $wgExtraNamespaces +
$this->namespaceNames
;
1735 $this->namespaceNames
[NS_PROJECT
] = $wgMetaNamespace;
1736 if ( $wgMetaNamespaceTalk ) {
1737 $this->namespaceNames
[NS_PROJECT_TALK
] = $wgMetaNamespaceTalk;
1739 $talk = $this->namespaceNames
[NS_PROJECT_TALK
];
1740 $talk = str_replace( '$1', $wgMetaNamespace, $talk );
1742 # Allow grammar transformations
1743 # Allowing full message-style parsing would make simple requests
1744 # such as action=raw much more expensive than they need to be.
1745 # This will hopefully cover most cases.
1746 $talk = preg_replace_callback( '/{{grammar:(.*?)\|(.*?)}}/i',
1747 array( &$this, 'replaceGrammarInNamespace' ), $talk );
1748 $talk = str_replace( ' ', '_', $talk );
1749 $this->namespaceNames
[NS_PROJECT_TALK
] = $talk;
1752 # The above mixing may leave namespaces out of canonical order.
1753 # Re-order by namespace ID number...
1754 ksort( $this->namespaceNames
);
1756 # Put namespace names and aliases into a hashtable.
1757 # If this is too slow, then we should arrange it so that it is done
1758 # before caching. The catch is that at pre-cache time, the above
1759 # class-specific fixup hasn't been done.
1760 $this->mNamespaceIds
= array();
1761 foreach ( $this->namespaceNames
as $index => $name ) {
1762 $this->mNamespaceIds
[$this->lc($name)] = $index;
1764 if ( $this->namespaceAliases
) {
1765 foreach ( $this->namespaceAliases
as $name => $index ) {
1766 $this->mNamespaceIds
[$this->lc($name)] = $index;
1769 if ( $wgNamespaceAliases ) {
1770 foreach ( $wgNamespaceAliases as $name => $index ) {
1771 $this->mNamespaceIds
[$this->lc($name)] = $index;
1775 if ( $this->defaultDateFormat
== 'dmy or mdy' ) {
1776 $this->defaultDateFormat
= $wgAmericanDates ?
'mdy' : 'dmy';
1778 wfProfileOut( __METHOD__
);
1781 function replaceGrammarInNamespace( $m ) {
1782 return $this->convertGrammar( trim( $m[2] ), trim( $m[1] ) );
1785 static function getCaseMaps() {
1786 static $wikiUpperChars, $wikiLowerChars;
1787 if ( isset( $wikiUpperChars ) ) {
1788 return array( $wikiUpperChars, $wikiLowerChars );
1791 wfProfileIn( __METHOD__
);
1792 $arr = wfGetPrecompiledData( 'Utf8Case.ser' );
1793 if ( $arr === false ) {
1794 throw new MWException(
1795 "Utf8Case.ser is missing, please run \"make\" in the serialized directory\n" );
1798 wfProfileOut( __METHOD__
);
1799 return array( $wikiUpperChars, $wikiLowerChars );