Updates and polishing
[mediawiki.git] / languages / Language.php
blob32441a8542e31b96f42ad7928fbe473386de5a5b
1 <?php
2 /**
3 * @package MediaWiki
4 * @subpackage Language
5 */
7 if( defined( 'MEDIAWIKI' ) ) {
10 # In general you should not make customizations in these language files
11 # directly, but should use the MediaWiki: special namespace to customize
12 # user interface messages through the wiki.
13 # See http://meta.wikipedia.org/wiki/MediaWiki_namespace
15 # NOTE TO TRANSLATORS: Do not copy this whole file when making translations!
16 # A lot of common constants and a base class with inheritable methods are
17 # defined here, which should not be redefined. See the other LanguageXx.php
18 # files for examples.
21 #--------------------------------------------------------------------------
22 # Language-specific text
23 #--------------------------------------------------------------------------
25 if($wgMetaNamespace === FALSE)
26 $wgMetaNamespace = str_replace( ' ', '_', $wgSitename );
28 /* private */ $wgNamespaceNamesEn = array(
29 NS_MEDIA => 'Media',
30 NS_SPECIAL => 'Special',
31 NS_MAIN => '',
32 NS_TALK => 'Talk',
33 NS_USER => 'User',
34 NS_USER_TALK => 'User_talk',
35 NS_PROJECT => $wgMetaNamespace,
36 NS_PROJECT_TALK => $wgMetaNamespace . '_talk',
37 NS_IMAGE => 'Image',
38 NS_IMAGE_TALK => 'Image_talk',
39 NS_MEDIAWIKI => 'MediaWiki',
40 NS_MEDIAWIKI_TALK => 'MediaWiki_talk',
41 NS_TEMPLATE => 'Template',
42 NS_TEMPLATE_TALK => 'Template_talk',
43 NS_HELP => 'Help',
44 NS_HELP_TALK => 'Help_talk',
45 NS_CATEGORY => 'Category',
46 NS_CATEGORY_TALK => 'Category_talk',
49 if(isset($wgExtraNamespaces)) {
50 $wgNamespaceNamesEn=$wgNamespaceNamesEn+$wgExtraNamespaces;
53 /* private */ $wgDefaultUserOptionsEn = array(
54 'quickbar' => 1,
55 'underline' => 2,
56 'cols' => 80,
57 'rows' => 25,
58 'searchlimit' => 20,
59 'contextlines' => 5,
60 'contextchars' => 50,
61 'skin' => $wgDefaultSkin,
62 'math' => 1,
63 'rcdays' => 7,
64 'rclimit' => 50,
65 'wllimit' => 250,
66 'highlightbroken' => 1,
67 'stubthreshold' => 0,
68 'previewontop' => 1,
69 'editsection' => 1,
70 'editsectiononrightclick'=> 0,
71 'showtoc' => 1,
72 'showtoolbar' => 1,
73 'date' => 0,
74 'imagesize' => 2,
75 'thumbsize' => 2,
76 'rememberpassword' => 0,
77 'enotifwatchlistpages' => 0,
78 'enotifusertalkpages' => 1,
79 'enotifminoredits' => 0,
80 'enotifrevealaddr' => 0,
81 'shownumberswatching' => 1,
82 'fancysig' => 0,
83 'externaleditor' => 0,
84 'externaldiff' => 0,
85 'showjumplinks' => 1,
86 'numberheadings' => 0,
87 'uselivepreview' => 0,
88 'watchlistdays' => 3.0,
91 /* private */ $wgQuickbarSettingsEn = array(
92 'None', 'Fixed left', 'Fixed right', 'Floating left', 'Floating right'
95 /* private */ $wgSkinNamesEn = array(
96 'standard' => 'Classic',
97 'nostalgia' => 'Nostalgia',
98 'cologneblue' => 'Cologne Blue',
99 'davinci' => 'DaVinci',
100 'mono' => 'Mono',
101 'monobook' => 'MonoBook',
102 'myskin' => 'MySkin',
103 'chick' => 'Chick'
106 /* private */ $wgMathNamesEn = array(
107 MW_MATH_PNG => 'mw_math_png',
108 MW_MATH_SIMPLE => 'mw_math_simple',
109 MW_MATH_HTML => 'mw_math_html',
110 MW_MATH_SOURCE => 'mw_math_source',
111 MW_MATH_MODERN => 'mw_math_modern',
112 MW_MATH_MATHML => 'mw_math_mathml'
116 * Whether to use user or default setting in Language::date()
118 * NOTE: the array string values are no longer important!
119 * The actual date format functions are now called for the selection in
120 * Special:Preferences, and the 'datedefault' message for MW_DATE_DEFAULT.
122 * The array keys make up the set of formats which this language allows
123 * the user to select. It's exposed via Language::getDateFormats().
125 * @private
127 $wgDateFormatsEn = array(
128 MW_DATE_DEFAULT => 'No preference',
129 MW_DATE_DMY => '16:12, 15 January 2001',
130 MW_DATE_MDY => '16:12, January 15, 2001',
131 MW_DATE_YMD => '16:12, 2001 January 15',
132 MW_DATE_ISO => '2001-01-15 16:12:34'
135 /* private */ $wgUserTogglesEn = array(
136 'highlightbroken',
137 'justify',
138 'hideminor',
139 'extendwatchlist',
140 'usenewrc',
141 'numberheadings',
142 'showtoolbar',
143 'editondblclick',
144 'editsection',
145 'editsectiononrightclick',
146 'showtoc',
147 'rememberpassword',
148 'editwidth',
149 'watchcreations',
150 'watchdefault',
151 'minordefault',
152 'previewontop',
153 'previewonfirst',
154 'nocache',
155 'enotifwatchlistpages',
156 'enotifusertalkpages',
157 'enotifminoredits',
158 'enotifrevealaddr',
159 'shownumberswatching',
160 'fancysig',
161 'externaleditor',
162 'externaldiff',
163 'showjumplinks',
164 'uselivepreview',
165 'autopatrol',
166 'forceeditsummary',
167 'watchlisthideown',
168 'watchlisthidebots',
171 /* private */ $wgBookstoreListEn = array(
172 'AddALL' => 'http://www.addall.com/New/Partner.cgi?query=$1&type=ISBN',
173 'PriceSCAN' => 'http://www.pricescan.com/books/bookDetail.asp?isbn=$1',
174 'Barnes & Noble' => 'http://search.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=$1',
175 'Amazon.com' => 'http://www.amazon.com/exec/obidos/ISBN=$1'
178 # Read language names
179 global $wgLanguageNames;
180 /** */
181 require_once( 'Names.php' );
183 $wgLanguageNamesEn =& $wgLanguageNames;
186 /* private */ $wgWeekdayNamesEn = array(
187 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
188 'friday', 'saturday'
192 /* private */ $wgMonthNamesEn = array(
193 'january', 'february', 'march', 'april', 'may_long', 'june',
194 'july', 'august', 'september', 'october', 'november',
195 'december'
197 /* private */ $wgMonthNamesGenEn = array(
198 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen',
199 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen',
200 'december-gen'
203 /* private */ $wgMonthAbbreviationsEn = array(
204 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug',
205 'sep', 'oct', 'nov', 'dec'
208 # Note to translators:
209 # Please include the English words as synonyms. This allows people
210 # from other wikis to contribute more easily.
212 /* private */ $wgMagicWordsEn = array(
213 # ID CASE SYNONYMS
214 MAG_REDIRECT => array( 0, '#REDIRECT' ),
215 MAG_NOTOC => array( 0, '__NOTOC__' ),
216 MAG_FORCETOC => array( 0, '__FORCETOC__' ),
217 MAG_TOC => array( 0, '__TOC__' ),
218 MAG_NOEDITSECTION => array( 0, '__NOEDITSECTION__' ),
219 MAG_START => array( 0, '__START__' ),
220 MAG_CURRENTMONTH => array( 1, 'CURRENTMONTH' ),
221 MAG_CURRENTMONTHNAME => array( 1, 'CURRENTMONTHNAME' ),
222 MAG_CURRENTMONTHNAMEGEN => array( 1, 'CURRENTMONTHNAMEGEN' ),
223 MAG_CURRENTMONTHABBREV => array( 1, 'CURRENTMONTHABBREV' ),
224 MAG_CURRENTDAY => array( 1, 'CURRENTDAY' ),
225 MAG_CURRENTDAY2 => array( 1, 'CURRENTDAY2' ),
226 MAG_CURRENTDAYNAME => array( 1, 'CURRENTDAYNAME' ),
227 MAG_CURRENTYEAR => array( 1, 'CURRENTYEAR' ),
228 MAG_CURRENTTIME => array( 1, 'CURRENTTIME' ),
229 MAG_NUMBEROFARTICLES => array( 1, 'NUMBEROFARTICLES' ),
230 MAG_NUMBEROFFILES => array( 1, 'NUMBEROFFILES' ),
231 MAG_PAGENAME => array( 1, 'PAGENAME' ),
232 MAG_PAGENAMEE => array( 1, 'PAGENAMEE' ),
233 MAG_NAMESPACE => array( 1, 'NAMESPACE' ),
234 MAG_NAMESPACEE => array( 1, 'NAMESPACEE' ),
235 MAG_TALKSPACE => array( 1, 'TALKSPACE' ),
236 MAG_TALKSPACEE => array( 1, 'TALKSPACEE' ),
237 MAG_SUBJECTSPACE => array( 1, 'SUBJECTSPACE', 'ARTICLESPACE' ),
238 MAG_SUBJECTSPACEE => array( 1, 'SUBJECTSPACEE', 'ARTICLESPACEE' ),
239 MAG_FULLPAGENAME => array( 1, 'FULLPAGENAME' ),
240 MAG_FULLPAGENAMEE => array( 1, 'FULLPAGENAMEE' ),
241 MAG_SUBPAGENAME => array( 1, 'SUBPAGENAME' ),
242 MAG_SUBPAGENAMEE => array( 1, 'SUBPAGENAMEE' ),
243 MAG_TALKPAGENAME => array( 1, 'TALKPAGENAME' ),
244 MAG_TALKPAGENAMEE => array( 1, 'TALKPAGENAMEE' ),
245 MAG_SUBJECTPAGENAME => array( 1, 'SUBJECTPAGENAME', 'ARTICLEPAGENAME' ),
246 MAG_SUBJECTPAGENAMEE => array( 1, 'SUBJECTPAGENAMEE', 'ARTICLEPAGENAMEE' ),
247 MAG_MSG => array( 0, 'MSG:' ),
248 MAG_SUBST => array( 0, 'SUBST:' ),
249 MAG_MSGNW => array( 0, 'MSGNW:' ),
250 MAG_END => array( 0, '__END__' ),
251 MAG_IMG_THUMBNAIL => array( 1, 'thumbnail', 'thumb' ),
252 MAG_IMG_MANUALTHUMB => array( 1, 'thumbnail=$1', 'thumb=$1'),
253 MAG_IMG_RIGHT => array( 1, 'right' ),
254 MAG_IMG_LEFT => array( 1, 'left' ),
255 MAG_IMG_NONE => array( 1, 'none' ),
256 MAG_IMG_WIDTH => array( 1, '$1px' ),
257 MAG_IMG_CENTER => array( 1, 'center', 'centre' ),
258 MAG_IMG_FRAMED => array( 1, 'framed', 'enframed', 'frame' ),
259 MAG_INT => array( 0, 'INT:' ),
260 MAG_SITENAME => array( 1, 'SITENAME' ),
261 MAG_NS => array( 0, 'NS:' ),
262 MAG_LOCALURL => array( 0, 'LOCALURL:' ),
263 MAG_LOCALURLE => array( 0, 'LOCALURLE:' ),
264 MAG_SERVER => array( 0, 'SERVER' ),
265 MAG_SERVERNAME => array( 0, 'SERVERNAME' ),
266 MAG_SCRIPTPATH => array( 0, 'SCRIPTPATH' ),
267 MAG_GRAMMAR => array( 0, 'GRAMMAR:' ),
268 MAG_NOTITLECONVERT => array( 0, '__NOTITLECONVERT__', '__NOTC__'),
269 MAG_NOCONTENTCONVERT => array( 0, '__NOCONTENTCONVERT__', '__NOCC__'),
270 MAG_CURRENTWEEK => array( 1, 'CURRENTWEEK' ),
271 MAG_CURRENTDOW => array( 1, 'CURRENTDOW' ),
272 MAG_REVISIONID => array( 1, 'REVISIONID' ),
273 MAG_PLURAL => array( 0, 'PLURAL:' ),
274 MAG_FULLURL => array( 0, 'FULLURL:' ),
275 MAG_FULLURLE => array( 0, 'FULLURLE:' ),
276 MAG_LCFIRST => array( 0, 'LCFIRST:' ),
277 MAG_UCFIRST => array( 0, 'UCFIRST:' ),
278 MAG_LC => array( 0, 'LC:' ),
279 MAG_UC => array( 0, 'UC:' ),
280 MAG_RAW => array( 0, 'RAW:' ),
281 MAG_DISPLAYTITLE => array( 1, 'DISPLAYTITLE' ),
284 if (!$wgCachedMessageArrays) {
285 require_once('Messages.php');
288 /* a fake language converter */
289 class fakeConverter {
290 var $mLang;
291 function fakeConverter($langobj) {$this->mLang = $langobj;}
292 function convert($t, $i) {return $t;}
293 function parserConvert($t, $p) {return $t;}
294 function getVariants() { return array( $this->mLang->getCode() ); }
295 function getPreferredVariant() {return $this->mLang->getCode(); }
296 function findVariantLink(&$l, &$n) {}
297 function getExtraHashOptions() {return '';}
298 function getParsedTitle() {return '';}
299 function markNoConversion($text) {return $text;}
300 function convertCategoryKey( $key ) {return $key; }
304 #--------------------------------------------------------------------------
305 # Internationalisation code
306 #--------------------------------------------------------------------------
308 class Language {
309 var $mConverter;
310 function Language() {
312 # Copies any missing values in the specified arrays from En to the current language
313 $fillin = array( 'wgSysopSpecialPages', 'wgValidSpecialPages', 'wgDeveloperSpecialPages' );
314 $name = get_class( $this );
316 if( strpos( $name, 'language' ) == 0){
317 $lang = ucfirst( substr( $name, 8 ) );
318 foreach( $fillin as $arrname ){
319 $langver = "{$arrname}{$lang}";
320 $enver = "{$arrname}En";
321 if( ! isset( $GLOBALS[$langver] ) || ! isset( $GLOBALS[$enver] ))
322 continue;
323 foreach($GLOBALS[$enver] as $spage => $text){
324 if( ! isset( $GLOBALS[$langver][$spage] ) )
325 $GLOBALS[$langver][$spage] = $text;
329 $this->mConverter = new fakeConverter($this);
333 * Exports the default user options as defined in
334 * $wgDefaultUserOptionsEn, user preferences can override some of these
335 * depending on what's in (Local|Default)Settings.php and some defines.
337 * @return array
339 function getDefaultUserOptions() {
340 global $wgDefaultUserOptionsEn ;
341 return $wgDefaultUserOptionsEn ;
345 * Exports $wgBookstoreListEn
346 * @return array
348 function getBookstoreList() {
349 global $wgBookstoreListEn ;
350 return $wgBookstoreListEn ;
354 * @return array
356 function getNamespaces() {
357 global $wgNamespaceNamesEn;
358 return $wgNamespaceNamesEn;
362 * A convenience function that returns the same thing as
363 * getNamespaces() except with the array values changed to ' '
364 * where it found '_', useful for producing output to be displayed
365 * e.g. in <select> forms.
367 * @return array
369 function getFormattedNamespaces() {
370 $ns = $this->getNamespaces();
371 foreach($ns as $k => $v) {
372 $ns[$k] = strtr($v, '_', ' ');
374 return $ns;
378 * Get a namespace value by key
379 * <code>
380 * $mw_ns = $wgContLang->getNsText( NS_MEDIAWIKI );
381 * echo $mw_ns; // prints 'MediaWiki'
382 * </code>
384 * @param int $index the array key of the namespace to return
385 * @return mixed, string if the namespace value exists, otherwise false
387 function getNsText( $index ) {
388 $ns = $this->getNamespaces();
389 return isset( $ns[$index] ) ? $ns[$index] : false;
393 * A convenience function that returns the same thing as
394 * getNsText() except with '_' changed to ' ', useful for
395 * producing output.
397 * @return array
399 function getFormattedNsText( $index ) {
400 $ns = $this->getNsText( $index );
401 return strtr($ns, '_', ' ');
405 * Get a namespace key by value, case insensetive.
407 * @param string $text
408 * @return mixed An integer if $text is a valid value otherwise false
410 function getNsIndex( $text ) {
411 $ns = $this->getNamespaces();
413 foreach ( $ns as $i => $n ) {
414 if ( strcasecmp( $n, $text ) == 0)
415 return $i;
417 return false;
421 * short names for language variants used for language conversion links.
423 * @param string $code
424 * @return string
426 function getVariantname( $code ) {
427 return wfMsg( "variantname-$code" );
430 function specialPage( $name ) {
431 return $this->getNsText(NS_SPECIAL) . ':' . $name;
434 function getQuickbarSettings() {
435 global $wgQuickbarSettingsEn;
436 return $wgQuickbarSettingsEn;
439 function getSkinNames() {
440 global $wgSkinNamesEn;
441 return $wgSkinNamesEn;
444 function getMathNames() {
445 global $wgMathNamesEn;
446 return $wgMathNamesEn;
449 function getDateFormats() {
450 global $wgDateFormatsEn;
451 return $wgDateFormatsEn;
454 function getUserToggles() {
455 global $wgUserTogglesEn;
456 return $wgUserTogglesEn;
459 function getUserToggle( $tog ) {
460 return wfMsg( "tog-$tog" );
463 function getLanguageNames() {
464 global $wgLanguageNamesEn;
465 return $wgLanguageNamesEn;
468 function getLanguageName( $code ) {
469 global $wgLanguageNamesEn;
470 if ( ! array_key_exists( $code, $wgLanguageNamesEn ) ) {
471 return '';
473 return $wgLanguageNamesEn[$code];
476 function getMonthName( $key ) {
477 global $wgMonthNamesEn, $wgContLang;
478 // see who called us and use the correct message function
479 if( get_class( $wgContLang->getLangObj() ) == get_class( $this ) )
480 return wfMsgForContent($wgMonthNamesEn[$key-1]);
481 else
482 return wfMsg($wgMonthNamesEn[$key-1]);
485 /* by default we just return base form */
486 function getMonthNameGen( $key ) {
487 return $this->getMonthName( $key );
490 function getMonthAbbreviation( $key ) {
491 global $wgMonthAbbreviationsEn, $wgContLang;
492 // see who called us and use the correct message function
493 if( get_class( $wgContLang->getLangObj() ) == get_class( $this ) )
494 return wfMsgForContent(@$wgMonthAbbreviationsEn[$key-1]);
495 else
496 return wfMsg(@$wgMonthAbbreviationsEn[$key-1]);
499 function getWeekdayName( $key ) {
500 global $wgWeekdayNamesEn, $wgContLang;
501 // see who called us and use the correct message function
502 if( get_class( $wgContLang->getLangObj() ) == get_class( $this ) )
503 return wfMsgForContent($wgWeekdayNamesEn[$key-1]);
504 else
505 return wfMsg($wgWeekdayNamesEn[$key-1]);
509 * Used by date() and time() to adjust the time output.
510 * @public
511 * @param int $ts the time in date('YmdHis') format
512 * @param mixed $tz adjust the time by this amount (default false,
513 * mean we get user timecorrection setting)
514 * @return int
517 function userAdjust( $ts, $tz = false ) {
518 global $wgUser, $wgLocalTZoffset;
520 if (!$tz) {
521 $tz = $wgUser->getOption( 'timecorrection' );
524 # minutes and hours differences:
525 $minDiff = 0;
526 $hrDiff = 0;
528 if ( $tz === '' ) {
529 $hrDiff = isset( $wgLocalTZoffset ) ? $wgLocalTZoffset : 0;
530 } elseif ( strpos( $tz, ':' ) !== false ) {
531 $tzArray = explode( ':', $tz );
532 $hrDiff = intval($tzArray[0]);
533 $minDiff = intval($hrDiff < 0 ? -$tzArray[1] : $tzArray[1]);
534 } else {
535 $hrDiff = intval( $tz );
538 # No difference ? Return time unchanged
539 if ( 0 == $hrDiff && 0 == $minDiff ) { return $ts; }
541 # Generate an adjusted date
542 $t = mktime( (
543 (int)substr( $ts, 8, 2) ) + $hrDiff, # Hours
544 (int)substr( $ts, 10, 2 ) + $minDiff, # Minutes
545 (int)substr( $ts, 12, 2 ), # Seconds
546 (int)substr( $ts, 4, 2 ), # Month
547 (int)substr( $ts, 6, 2 ), # Day
548 (int)substr( $ts, 0, 4 ) ); #Year
549 return date( 'YmdHis', $t );
553 * This is meant to be used by time(), date(), and timeanddate() to get
554 * the date preference they're supposed to use, it should be used in
555 * all children.
557 *<code>
558 * function timeanddate([...], $format = true) {
559 * $datePreference = $this->dateFormat($format);
560 * [...]
561 *</code>
563 * @param mixed $usePrefs: if true, the user's preference is used
564 * if false, the site/language default is used
565 * if int/string, assumed to be a format.
566 * @return string
568 function dateFormat( $usePrefs = true ) {
569 global $wgUser;
571 if( is_bool( $usePrefs ) ) {
572 if( $usePrefs ) {
573 $datePreference = $wgUser->getOption( 'date' );
574 } else {
575 $options = $this->getDefaultUserOptions();
576 $datePreference = (string)$options['date'];
578 } else {
579 $datePreference = (string)$usePrefs;
582 // return int
583 if( $datePreference == '' ) {
584 return MW_DATE_DEFAULT;
587 return $datePreference;
591 * @public
592 * @param mixed $ts the time format which needs to be turned into a
593 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
594 * @param bool $adj whether to adjust the time output according to the
595 * user configured offset ($timecorrection)
596 * @param mixed $format true to use user's date format preference
597 * @param string $timecorrection the time offset as returned by
598 * validateTimeZone() in Special:Preferences
599 * @return string
601 function date( $ts, $adj = false, $format = true, $timecorrection = false ) {
602 global $wgUser, $wgAmericanDates;
604 if ( $adj ) { $ts = $this->userAdjust( $ts, $timecorrection ); }
606 $datePreference = $this->dateFormat( $format );
607 if( $datePreference == MW_DATE_DEFAULT ) {
608 $datePreference = $wgAmericanDates ? MW_DATE_MDY : MW_DATE_DMY;
611 $month = $this->formatMonth( substr( $ts, 4, 2 ), $datePreference );
612 $day = $this->formatDay( substr( $ts, 6, 2 ), $datePreference );
613 $year = $this->formatNum( substr( $ts, 0, 4 ), true );
615 switch( $datePreference ) {
616 case MW_DATE_DMY: return "$day $month $year";
617 case MW_DATE_YMD: return "$year $month $day";
618 case MW_DATE_ISO: return substr($ts, 0, 4). '-' . substr($ts, 4, 2). '-' .substr($ts, 6, 2);
619 default: return "$month $day, $year";
624 * @public
625 * @param mixed $ts the time format which needs to be turned into a
626 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
627 * @param bool $adj whether to adjust the time output according to the
628 * user configured offset ($timecorrection)
629 * @param mixed $format true to use user's date format preference
630 * @param string $timecorrection the time offset as returned by
631 * validateTimeZone() in Special:Preferences
632 * @return string
634 function time( $ts, $adj = false, $format = true, $timecorrection = false ) {
635 global $wgUser;
637 if ( $adj ) { $ts = $this->userAdjust( $ts, $timecorrection ); }
638 $datePreference = $this->dateFormat( $format );
640 $sep = ($datePreference == MW_DATE_ISO)
641 ? ':'
642 : $this->timeSeparator( $format );
644 $t = substr( $ts, 8, 2 ) . $sep . substr( $ts, 10, 2 );
646 if ( $datePreference == MW_DATE_ISO ) {
647 $t .= $sep . substr( $ts, 12, 2 );
649 return $t;
653 * Default separator character between hours, minutes, and seconds.
654 * Will be used by Language::time() for non-ISO formats.
655 * (ISO will always use a colon.)
656 * @return string
658 function timeSeparator( $format ) {
659 return ':';
663 * String to insert between the time and the date in a combined
664 * string. Should include any relevant whitespace.
665 * @return string
667 function timeDateSeparator( $format ) {
668 return ', ';
672 * Return true if the time should display before the date.
673 * @return bool
674 * @private
676 function timeBeforeDate() {
677 return true;
680 function formatMonth( $month, $format ) {
681 return $this->getMonthName( $month );
684 function formatDay( $day, $format ) {
685 return $this->formatNum( 0 + $day );
689 * @public
690 * @param mixed $ts the time format which needs to be turned into a
691 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
692 * @param bool $adj whether to adjust the time output according to the
693 * user configured offset ($timecorrection)
695 * @param mixed $format what format to return, if it's false output the
696 * default one (default true)
697 * @param string $timecorrection the time offset as returned by
698 * validateTimeZone() in Special:Preferences
699 * @return string
701 function timeanddate( $ts, $adj = false, $format = true, $timecorrection = false) {
702 global $wgUser;
704 $datePreference = $this->dateFormat($format);
705 switch ( $datePreference ) {
706 case MW_DATE_ISO: return $this->date( $ts, $adj, $format, $timecorrection ) . ' ' .
707 $this->time( $ts, $adj, $format, $timecorrection );
708 default:
709 $time = $this->time( $ts, $adj, $format, $timecorrection );
710 $sep = $this->timeDateSeparator( $datePreference );
711 $date = $this->date( $ts, $adj, $format, $timecorrection );
712 return $this->timeBeforeDate( $datePreference )
713 ? $time . $sep . $date
714 : $date . $sep . $time;
718 function getMessage( $key ) {
719 global $wgAllMessagesEn;
720 return @$wgAllMessagesEn[$key];
723 function getAllMessages() {
724 global $wgAllMessagesEn;
725 return $wgAllMessagesEn;
728 function iconv( $in, $out, $string ) {
729 # For most languages, this is a wrapper for iconv
730 return iconv( $in, $out, $string );
733 function ucfirst( $string ) {
734 # For most languages, this is a wrapper for ucfirst()
735 return ucfirst( $string );
738 function uc( $str ) {
739 return strtoupper( $str );
742 function lcfirst( $s ) {
743 return strtolower( $s{0} ). substr( $s, 1 );
746 function lc( $str ) {
747 return strtolower( $str );
750 function checkTitleEncoding( $s ) {
751 global $wgInputEncoding;
753 # Check for UTF-8 URLs; Internet Explorer produces these if you
754 # type non-ASCII chars in the URL bar or follow unescaped links.
755 $ishigh = preg_match( '/[\x80-\xff]/', $s);
756 $isutf = ($ishigh ? preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
757 '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s ) : true );
759 if( ($wgInputEncoding != 'utf-8') and $ishigh and $isutf )
760 return @iconv( 'UTF-8', $wgInputEncoding, $s );
762 if( ($wgInputEncoding == 'utf-8') and $ishigh and !$isutf )
763 return utf8_encode( $s );
765 # Other languages can safely leave this function, or replace
766 # it with one to detect and convert another legacy encoding.
767 return $s;
771 * Some languages have special punctuation to strip out
772 * or characters which need to be converted for MySQL's
773 * indexing to grok it correctly. Make such changes here.
775 * @param string $in
776 * @return string
778 function stripForSearch( $in ) {
779 return strtolower( $in );
782 function convertForSearchResult( $termsArray ) {
783 # some languages, e.g. Chinese, need to do a conversion
784 # in order for search results to be displayed correctly
785 return $termsArray;
789 * Get the first character of a string. In ASCII, return
790 * first byte of the string. UTF8 and others have to
791 * overload this.
793 * @param string $s
794 * @return string
796 function firstChar( $s ) {
797 return $s[0];
800 function initEncoding() {
801 # Some languages may have an alternate char encoding option
802 # (Esperanto X-coding, Japanese furigana conversion, etc)
803 # If this language is used as the primary content language,
804 # an override to the defaults can be set here on startup.
805 #global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
808 function setAltEncoding() {
809 # Some languages may have an alternate char encoding option
810 # (Esperanto X-coding, Japanese furigana conversion, etc)
811 # If 'altencoding' is checked in user prefs, this gives a
812 # chance to swap out the default encoding settings.
813 #global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
816 function recodeForEdit( $s ) {
817 # For some languages we'll want to explicitly specify
818 # which characters make it into the edit box raw
819 # or are converted in some way or another.
820 # Note that if wgOutputEncoding is different from
821 # wgInputEncoding, this text will be further converted
822 # to wgOutputEncoding.
823 global $wgInputEncoding, $wgEditEncoding;
824 if( $wgEditEncoding == '' or
825 $wgEditEncoding == $wgInputEncoding ) {
826 return $s;
827 } else {
828 return $this->iconv( $wgInputEncoding, $wgEditEncoding, $s );
832 function recodeInput( $s ) {
833 # Take the previous into account.
834 global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
835 if($wgEditEncoding != "") {
836 $enc = $wgEditEncoding;
837 } else {
838 $enc = $wgOutputEncoding;
840 if( $enc == $wgInputEncoding ) {
841 return $s;
842 } else {
843 return $this->iconv( $enc, $wgInputEncoding, $s );
848 * For right-to-left language support
850 * @return bool
852 function isRTL() { return false; }
855 * To allow "foo[[bar]]" to extend the link over the whole word "foobar"
857 * @return bool
859 function linkPrefixExtension() { return false; }
862 function &getMagicWords() {
863 global $wgMagicWordsEn;
864 return $wgMagicWordsEn;
867 # Fill a MagicWord object with data from here
868 function getMagic( &$mw ) {
869 $raw = $this->getMagicWords();
871 wfRunHooks( 'LanguageGetMagic', array( &$raw ) );
873 if( !isset( $raw[$mw->mId] ) ) {
874 # Fall back to English if local list is incomplete
875 $raw =& Language::getMagicWords();
877 $rawEntry = $raw[$mw->mId];
878 $mw->mCaseSensitive = $rawEntry[0];
879 $mw->mSynonyms = array_slice( $rawEntry, 1 );
883 * Italic is unsuitable for some languages
885 * @public
887 * @param string $text The text to be emphasized.
888 * @return string
890 function emphasize( $text ) {
891 return "<em>$text</em>";
895 * This function enables formatting of numbers, it should only come
896 * into effect when the $wgTranslateNumerals variable is TRUE.
898 * Normally we output all numbers in plain en_US style, that is
899 * 293,291.235 for twohundredninetythreethousand-twohundredninetyone
900 * point twohundredthirtyfive. However this is not sutable for all
901 * languages, some such as Pakaran want ੨੯੩,੨੯੫.੨੩੫ and others such as
902 * Icelandic just want to use commas instead of dots, and dots instead
903 * of commas like "293.291,235".
905 * An example of this function being called:
906 * <code>
907 * wfMsg( 'message', $wgLang->formatNum( $num ) )
908 * </code>
910 * See LanguageGu.php for the Gujarati implementation and
911 * LanguageIs.php for the , => . and . => , implementation.
913 * @todo check if it's viable to use localeconv() for the decimal
914 * seperator thing.
915 * @public
916 * @param mixed $number the string to be formatted, should be an integer or
917 * a floating point number.
918 * @param bool $year are we being passed a year? (turns off commafication)
919 * @return mixed whatever we're fed if it's a year, a string otherwise.
921 function formatNum( $number, $year = false ) {
922 return $year ? $number : $this->commafy($number);
926 * Adds commas to a given number
928 * @param mixed $_
929 * @return string
931 function commafy($_) {
932 return strrev((string)preg_replace('/(\d{3})(?=\d)(?!\d*\.)/','$1,',strrev($_)));
936 * For the credit list in includes/Credits.php (action=credits)
938 * @param array $l
939 * @return string
941 function listToText( $l ) {
942 $s = '';
943 $m = count($l) - 1;
944 for ($i = $m; $i >= 0; $i--) {
945 if ($i == $m) {
946 $s = $l[$i];
947 } else if ($i == $m - 1) {
948 $s = $l[$i] . ' ' . wfMsg('and') . ' ' . $s;
949 } else {
950 $s = $l[$i] . ', ' . $s;
953 return $s;
956 # Crop a string from the beginning or end to a certain number of bytes.
957 # (Bytes are used because our storage has limited byte lengths for some
958 # columns in the database.) Multibyte charsets will need to make sure that
959 # only whole characters are included!
961 # $length does not include the optional ellipsis.
962 # If $length is negative, snip from the beginning
963 function truncate( $string, $length, $ellipsis = '' ) {
964 if( $length == 0 ) {
965 return $ellipsis;
967 if ( strlen( $string ) <= abs( $length ) ) {
968 return $string;
970 if( $length > 0 ) {
971 $string = substr( $string, 0, $length );
972 return $string . $ellipsis;
973 } else {
974 $string = substr( $string, $length );
975 return $ellipsis . $string;
980 * Grammatical transformations, needed for inflected languages
981 * Invoked by putting {{grammar:case|word}} in a message
983 * @param string $word
984 * @param string $case
985 * @return string
987 function convertGrammar( $word, $case ) {
988 return $word;
992 * Plural form transformations, needed for some languages.
993 * For example, where are 3 form of plural in Russian and Polish,
994 * depending on "count mod 10". See [[w:Plural]]
995 * For English it is pretty simple.
997 * Invoked by putting {{plural:count|wordform1|wordform2}}
998 * or {{plural:count|wordform1|wordform2|wordform3}}
1000 * Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}}
1002 * @param integer $count
1003 * @param string $wordform1
1004 * @param string $wordform2
1005 * @param string $wordform3 (optional)
1006 * @return string
1008 function convertPlural( $count, $wordform1, $wordform2, $wordform3) {
1009 return $count == '1' ? $wordform1 : $wordform2;
1013 * For translaing of expiry times
1014 * @param string The validated block time in English
1015 * @return Somehow translated block time
1016 * @see LanguageFi.php for example implementation
1018 function translateBlockExpiry( $str ) {
1020 $scBlockExpiryOptions = wfMsg( 'ipboptions' );
1022 if ( $scBlockExpiryOptions == '-') {
1023 return $str;
1026 foreach (explode(',', $scBlockExpiryOptions) as $option) {
1027 if ( strpos($option, ":") === false )
1028 continue;
1029 list($show, $value) = explode(":", $option);
1030 if ( strcmp ( $str, $value) == 0 )
1031 return '<span title="' . htmlspecialchars($str). '">' .
1032 htmlspecialchars( trim( $show ) ) . '</span>';
1035 return $str;
1039 * languages like Chinese need to be segmented in order for the diff
1040 * to be of any use
1042 * @param string $text
1043 * @return string
1045 function segmentForDiff( $text ) {
1046 return $text;
1050 * and unsegment to show the result
1052 * @param string $text
1053 * @return string
1055 function unsegmentForDiff( $text ) {
1056 return $text;
1059 # convert text to different variants of a language.
1060 function convert( $text, $isTitle = false) {
1061 return $this->mConverter->convert($text, $isTitle);
1064 # Convert text from within Parser
1065 function parserConvert( $text, &$parser ) {
1066 return $this->mConverter->parserConvert( $text, $parser );
1070 * Perform output conversion on a string, and encode for safe HTML output.
1071 * @param string $text
1072 * @param bool $isTitle -- wtf?
1073 * @return string
1074 * @todo this should get integrated somewhere sane
1076 function convertHtml( $text, $isTitle = false ) {
1077 return htmlspecialchars( $this->convert( $text, $isTitle ) );
1080 function convertCategoryKey( $key ) {
1081 return $this->mConverter->convertCategoryKey( $key );
1085 * get the list of variants supported by this langauge
1086 * see sample implementation in LanguageZh.php
1088 * @return array an array of language codes
1090 function getVariants() {
1091 return $this->mConverter->getVariants();
1095 function getPreferredVariant() {
1096 return $this->mConverter->getPreferredVariant();
1100 * if a language supports multiple variants, it is
1101 * possible that non-existing link in one variant
1102 * actually exists in another variant. this function
1103 * tries to find it. See e.g. LanguageZh.php
1105 * @param string $link the name of the link
1106 * @param mixed $nt the title object of the link
1107 * @return null the input parameters may be modified upon return
1109 function findVariantLink( &$link, &$nt ) {
1110 $this->mConverter->findVariantLink($link, $nt);
1114 * returns language specific options used by User::getPageRenderHash()
1115 * for example, the preferred language variant
1117 * @return string
1118 * @public
1120 function getExtraHashOptions() {
1121 return $this->mConverter->getExtraHashOptions();
1125 * for languages that support multiple variants, the title of an
1126 * article may be displayed differently in different variants. this
1127 * function returns the apporiate title defined in the body of the article.
1129 * @return string
1131 function getParsedTitle() {
1132 return $this->mConverter->getParsedTitle();
1136 * Enclose a string with the "no conversion" tag. This is used by
1137 * various functions in the Parser
1139 * @param string $text text to be tagged for no conversion
1140 * @return string the tagged text
1142 function markNoConversion( $text ) {
1143 return $this->mConverter->markNoConversion( $text );
1147 * A regular expression to match legal word-trailing characters
1148 * which should be merged onto a link of the form [[foo]]bar.
1150 * @return string
1151 * @public
1153 function linkTrail() {
1154 return $this->getMessage( 'linktrail' );
1157 function getLangObj() {
1158 return $this;
1162 * Get the RFC 3066 code for this language object
1164 function getCode() {
1165 return str_replace( '_', '-', strtolower( substr( get_class( $this ), 8 ) ) );
1171 # FIXME: Merge all UTF-8 support code into Language base class.
1172 # We no longer support Latin-1 charset.
1173 require_once( 'LanguageUtf8.php' );
1175 # This should fail gracefully if there's not a localization available
1176 wfSuppressWarnings();
1177 // Preload base classes to work around APC/PHP5 bug
1178 include_once( 'Language' . str_replace( '-', '_', ucfirst( $wgLanguageCode ) ) . '.deps.php' );
1179 include_once( 'Language' . str_replace( '-', '_', ucfirst( $wgLanguageCode ) ) . '.php' );
1180 wfRestoreWarnings();