Fix #5191: $wgLocalTZoffset rounds time zones half an hour ahead of UTC
[lhc/web/wiklou.git] / languages / Language.php
1 <?php
2 /**
3 * @package MediaWiki
4 * @subpackage Language
5 */
6
7 if( defined( 'MEDIAWIKI' ) ) {
8
9 #
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
14 #
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.
19 #
20
21 #--------------------------------------------------------------------------
22 # Language-specific text
23 #--------------------------------------------------------------------------
24
25 if($wgMetaNamespace === FALSE)
26 $wgMetaNamespace = str_replace( ' ', '_', $wgSitename );
27
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',
47 );
48
49 if(isset($wgExtraNamespaces)) {
50 $wgNamespaceNamesEn=$wgNamespaceNamesEn+$wgExtraNamespaces;
51 }
52
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,
89 );
90
91 /* private */ $wgQuickbarSettingsEn = array(
92 'None', 'Fixed left', 'Fixed right', 'Floating left', 'Floating right'
93 );
94
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'
104 );
105
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'
113 );
114
115 /**
116 * Whether to use user or default setting in Language::date()
117 *
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.
121 *
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().
124 *
125 * @private
126 */
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'
133 );
134
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',
169 );
170
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'
176 );
177
178 # Read language names
179 global $wgLanguageNames;
180 /** */
181 require_once( 'Names.php' );
182
183 $wgLanguageNamesEn =& $wgLanguageNames;
184
185
186 /* private */ $wgWeekdayNamesEn = array(
187 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
188 'friday', 'saturday'
189 );
190
191
192 /* private */ $wgMonthNamesEn = array(
193 'january', 'february', 'march', 'april', 'may_long', 'june',
194 'july', 'august', 'september', 'october', 'november',
195 'december'
196 );
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'
201 );
202
203 /* private */ $wgMonthAbbreviationsEn = array(
204 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug',
205 'sep', 'oct', 'nov', 'dec'
206 );
207
208 # Note to translators:
209 # Please include the English words as synonyms. This allows people
210 # from other wikis to contribute more easily.
211 #
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_NUMBEROFUSERS => array( 1, 'NUMBEROFUSERS' ),
232 MAG_PAGENAME => array( 1, 'PAGENAME' ),
233 MAG_PAGENAMEE => array( 1, 'PAGENAMEE' ),
234 MAG_NAMESPACE => array( 1, 'NAMESPACE' ),
235 MAG_NAMESPACEE => array( 1, 'NAMESPACEE' ),
236 MAG_TALKSPACE => array( 1, 'TALKSPACE' ),
237 MAG_TALKSPACEE => array( 1, 'TALKSPACEE' ),
238 MAG_SUBJECTSPACE => array( 1, 'SUBJECTSPACE', 'ARTICLESPACE' ),
239 MAG_SUBJECTSPACEE => array( 1, 'SUBJECTSPACEE', 'ARTICLESPACEE' ),
240 MAG_FULLPAGENAME => array( 1, 'FULLPAGENAME' ),
241 MAG_FULLPAGENAMEE => array( 1, 'FULLPAGENAMEE' ),
242 MAG_SUBPAGENAME => array( 1, 'SUBPAGENAME' ),
243 MAG_SUBPAGENAMEE => array( 1, 'SUBPAGENAMEE' ),
244 MAG_TALKPAGENAME => array( 1, 'TALKPAGENAME' ),
245 MAG_TALKPAGENAMEE => array( 1, 'TALKPAGENAMEE' ),
246 MAG_SUBJECTPAGENAME => array( 1, 'SUBJECTPAGENAME', 'ARTICLEPAGENAME' ),
247 MAG_SUBJECTPAGENAMEE => array( 1, 'SUBJECTPAGENAMEE', 'ARTICLEPAGENAMEE' ),
248 MAG_MSG => array( 0, 'MSG:' ),
249 MAG_SUBST => array( 0, 'SUBST:' ),
250 MAG_MSGNW => array( 0, 'MSGNW:' ),
251 MAG_END => array( 0, '__END__' ),
252 MAG_IMG_THUMBNAIL => array( 1, 'thumbnail', 'thumb' ),
253 MAG_IMG_MANUALTHUMB => array( 1, 'thumbnail=$1', 'thumb=$1'),
254 MAG_IMG_RIGHT => array( 1, 'right' ),
255 MAG_IMG_LEFT => array( 1, 'left' ),
256 MAG_IMG_NONE => array( 1, 'none' ),
257 MAG_IMG_WIDTH => array( 1, '$1px' ),
258 MAG_IMG_CENTER => array( 1, 'center', 'centre' ),
259 MAG_IMG_FRAMED => array( 1, 'framed', 'enframed', 'frame' ),
260 MAG_INT => array( 0, 'INT:' ),
261 MAG_SITENAME => array( 1, 'SITENAME' ),
262 MAG_NS => array( 0, 'NS:' ),
263 MAG_LOCALURL => array( 0, 'LOCALURL:' ),
264 MAG_LOCALURLE => array( 0, 'LOCALURLE:' ),
265 MAG_SERVER => array( 0, 'SERVER' ),
266 MAG_SERVERNAME => array( 0, 'SERVERNAME' ),
267 MAG_SCRIPTPATH => array( 0, 'SCRIPTPATH' ),
268 MAG_GRAMMAR => array( 0, 'GRAMMAR:' ),
269 MAG_NOTITLECONVERT => array( 0, '__NOTITLECONVERT__', '__NOTC__'),
270 MAG_NOCONTENTCONVERT => array( 0, '__NOCONTENTCONVERT__', '__NOCC__'),
271 MAG_CURRENTWEEK => array( 1, 'CURRENTWEEK' ),
272 MAG_CURRENTDOW => array( 1, 'CURRENTDOW' ),
273 MAG_REVISIONID => array( 1, 'REVISIONID' ),
274 MAG_PLURAL => array( 0, 'PLURAL:' ),
275 MAG_FULLURL => array( 0, 'FULLURL:' ),
276 MAG_FULLURLE => array( 0, 'FULLURLE:' ),
277 MAG_LCFIRST => array( 0, 'LCFIRST:' ),
278 MAG_UCFIRST => array( 0, 'UCFIRST:' ),
279 MAG_LC => array( 0, 'LC:' ),
280 MAG_UC => array( 0, 'UC:' ),
281 MAG_RAW => array( 0, 'RAW:' ),
282 MAG_DISPLAYTITLE => array( 1, 'DISPLAYTITLE' ),
283 );
284
285 if (!$wgCachedMessageArrays) {
286 require_once('Messages.php');
287 }
288
289 /* a fake language converter */
290 class fakeConverter {
291 var $mLang;
292 function fakeConverter($langobj) {$this->mLang = $langobj;}
293 function convert($t, $i) {return $t;}
294 function parserConvert($t, $p) {return $t;}
295 function getVariants() { return array( $this->mLang->getCode() ); }
296 function getPreferredVariant() {return $this->mLang->getCode(); }
297 function findVariantLink(&$l, &$n) {}
298 function getExtraHashOptions() {return '';}
299 function getParsedTitle() {return '';}
300 function markNoConversion($text) {return $text;}
301 function convertCategoryKey( $key ) {return $key; }
302
303 }
304
305 #--------------------------------------------------------------------------
306 # Internationalisation code
307 #--------------------------------------------------------------------------
308
309 class Language {
310 var $mConverter;
311 function Language() {
312
313 # Copies any missing values in the specified arrays from En to the current language
314 $fillin = array( 'wgSysopSpecialPages', 'wgValidSpecialPages', 'wgDeveloperSpecialPages' );
315 $name = get_class( $this );
316
317 if( strpos( $name, 'language' ) == 0){
318 $lang = ucfirst( substr( $name, 8 ) );
319 foreach( $fillin as $arrname ){
320 $langver = "{$arrname}{$lang}";
321 $enver = "{$arrname}En";
322 if( ! isset( $GLOBALS[$langver] ) || ! isset( $GLOBALS[$enver] ))
323 continue;
324 foreach($GLOBALS[$enver] as $spage => $text){
325 if( ! isset( $GLOBALS[$langver][$spage] ) )
326 $GLOBALS[$langver][$spage] = $text;
327 }
328 }
329 }
330 $this->mConverter = new fakeConverter($this);
331 }
332
333 /**
334 * Exports the default user options as defined in
335 * $wgDefaultUserOptionsEn, user preferences can override some of these
336 * depending on what's in (Local|Default)Settings.php and some defines.
337 *
338 * @return array
339 */
340 function getDefaultUserOptions() {
341 global $wgDefaultUserOptionsEn ;
342 return $wgDefaultUserOptionsEn ;
343 }
344
345 /**
346 * Exports $wgBookstoreListEn
347 * @return array
348 */
349 function getBookstoreList() {
350 global $wgBookstoreListEn ;
351 return $wgBookstoreListEn ;
352 }
353
354 /**
355 * @return array
356 */
357 function getNamespaces() {
358 global $wgNamespaceNamesEn;
359 return $wgNamespaceNamesEn;
360 }
361
362 /**
363 * A convenience function that returns the same thing as
364 * getNamespaces() except with the array values changed to ' '
365 * where it found '_', useful for producing output to be displayed
366 * e.g. in <select> forms.
367 *
368 * @return array
369 */
370 function getFormattedNamespaces() {
371 $ns = $this->getNamespaces();
372 foreach($ns as $k => $v) {
373 $ns[$k] = strtr($v, '_', ' ');
374 }
375 return $ns;
376 }
377
378 /**
379 * Get a namespace value by key
380 * <code>
381 * $mw_ns = $wgContLang->getNsText( NS_MEDIAWIKI );
382 * echo $mw_ns; // prints 'MediaWiki'
383 * </code>
384 *
385 * @param int $index the array key of the namespace to return
386 * @return mixed, string if the namespace value exists, otherwise false
387 */
388 function getNsText( $index ) {
389 $ns = $this->getNamespaces();
390 return isset( $ns[$index] ) ? $ns[$index] : false;
391 }
392
393 /**
394 * A convenience function that returns the same thing as
395 * getNsText() except with '_' changed to ' ', useful for
396 * producing output.
397 *
398 * @return array
399 */
400 function getFormattedNsText( $index ) {
401 $ns = $this->getNsText( $index );
402 return strtr($ns, '_', ' ');
403 }
404
405 /**
406 * Get a namespace key by value, case insensetive.
407 *
408 * @param string $text
409 * @return mixed An integer if $text is a valid value otherwise false
410 */
411 function getNsIndex( $text ) {
412 $ns = $this->getNamespaces();
413
414 foreach ( $ns as $i => $n ) {
415 if ( strcasecmp( $n, $text ) == 0)
416 return $i;
417 }
418 return false;
419 }
420
421 /**
422 * short names for language variants used for language conversion links.
423 *
424 * @param string $code
425 * @return string
426 */
427 function getVariantname( $code ) {
428 return wfMsg( "variantname-$code" );
429 }
430
431 function specialPage( $name ) {
432 return $this->getNsText(NS_SPECIAL) . ':' . $name;
433 }
434
435 function getQuickbarSettings() {
436 global $wgQuickbarSettingsEn;
437 return $wgQuickbarSettingsEn;
438 }
439
440 function getSkinNames() {
441 global $wgSkinNamesEn;
442 return $wgSkinNamesEn;
443 }
444
445 function getMathNames() {
446 global $wgMathNamesEn;
447 return $wgMathNamesEn;
448 }
449
450 function getDateFormats() {
451 global $wgDateFormatsEn;
452 return $wgDateFormatsEn;
453 }
454
455 function getUserToggles() {
456 global $wgUserTogglesEn;
457 return $wgUserTogglesEn;
458 }
459
460 function getUserToggle( $tog ) {
461 return wfMsg( "tog-$tog" );
462 }
463
464 function getLanguageNames() {
465 global $wgLanguageNamesEn;
466 return $wgLanguageNamesEn;
467 }
468
469 function getLanguageName( $code ) {
470 global $wgLanguageNamesEn;
471 if ( ! array_key_exists( $code, $wgLanguageNamesEn ) ) {
472 return '';
473 }
474 return $wgLanguageNamesEn[$code];
475 }
476
477 function getMonthName( $key ) {
478 global $wgMonthNamesEn, $wgContLang;
479 // see who called us and use the correct message function
480 if( get_class( $wgContLang->getLangObj() ) == get_class( $this ) )
481 return wfMsgForContent($wgMonthNamesEn[$key-1]);
482 else
483 return wfMsg($wgMonthNamesEn[$key-1]);
484 }
485
486 /* by default we just return base form */
487 function getMonthNameGen( $key ) {
488 return $this->getMonthName( $key );
489 }
490
491 function getMonthAbbreviation( $key ) {
492 global $wgMonthAbbreviationsEn, $wgContLang;
493 // see who called us and use the correct message function
494 if( get_class( $wgContLang->getLangObj() ) == get_class( $this ) )
495 return wfMsgForContent(@$wgMonthAbbreviationsEn[$key-1]);
496 else
497 return wfMsg(@$wgMonthAbbreviationsEn[$key-1]);
498 }
499
500 function getWeekdayName( $key ) {
501 global $wgWeekdayNamesEn, $wgContLang;
502 // see who called us and use the correct message function
503 if( get_class( $wgContLang->getLangObj() ) == get_class( $this ) )
504 return wfMsgForContent($wgWeekdayNamesEn[$key-1]);
505 else
506 return wfMsg($wgWeekdayNamesEn[$key-1]);
507 }
508
509 /**
510 * Used by date() and time() to adjust the time output.
511 * @public
512 * @param int $ts the time in date('YmdHis') format
513 * @param mixed $tz adjust the time by this amount (default false,
514 * mean we get user timecorrection setting)
515 * @return int
516
517 */
518 function userAdjust( $ts, $tz = false ) {
519 global $wgUser, $wgLocalTZoffset;
520
521 if (!$tz) {
522 $tz = $wgUser->getOption( 'timecorrection' );
523 }
524
525 # minutes and hours differences:
526 $minDiff = 0;
527 $hrDiff = 0;
528
529 if ( $tz === '' ) {
530 # Global offset in minutes.
531 if( isset($wgLocalTZoffset) ) {
532 $hrDiff = $wgLocalTZoffset % 60;
533 $minDiff = $wgLocalTZoffset - ($hrDiff * 60);
534 }
535 } elseif ( strpos( $tz, ':' ) !== false ) {
536 $tzArray = explode( ':', $tz );
537 $hrDiff = intval($tzArray[0]);
538 $minDiff = intval($hrDiff < 0 ? -$tzArray[1] : $tzArray[1]);
539 } else {
540 $hrDiff = intval( $tz );
541 }
542
543 # No difference ? Return time unchanged
544 if ( 0 == $hrDiff && 0 == $minDiff ) { return $ts; }
545
546 # Generate an adjusted date
547 $t = mktime( (
548 (int)substr( $ts, 8, 2) ) + $hrDiff, # Hours
549 (int)substr( $ts, 10, 2 ) + $minDiff, # Minutes
550 (int)substr( $ts, 12, 2 ), # Seconds
551 (int)substr( $ts, 4, 2 ), # Month
552 (int)substr( $ts, 6, 2 ), # Day
553 (int)substr( $ts, 0, 4 ) ); #Year
554 return date( 'YmdHis', $t );
555 }
556
557 /**
558 * This is meant to be used by time(), date(), and timeanddate() to get
559 * the date preference they're supposed to use, it should be used in
560 * all children.
561 *
562 *<code>
563 * function timeanddate([...], $format = true) {
564 * $datePreference = $this->dateFormat($format);
565 * [...]
566 *</code>
567 *
568 * @param mixed $usePrefs: if true, the user's preference is used
569 * if false, the site/language default is used
570 * if int/string, assumed to be a format.
571 * @return string
572 */
573 function dateFormat( $usePrefs = true ) {
574 global $wgUser;
575
576 if( is_bool( $usePrefs ) ) {
577 if( $usePrefs ) {
578 $datePreference = $wgUser->getOption( 'date' );
579 } else {
580 $options = $this->getDefaultUserOptions();
581 $datePreference = (string)$options['date'];
582 }
583 } else {
584 $datePreference = (string)$usePrefs;
585 }
586
587 // return int
588 if( $datePreference == '' ) {
589 return MW_DATE_DEFAULT;
590 }
591
592 return $datePreference;
593 }
594
595 /**
596 * @public
597 * @param mixed $ts the time format which needs to be turned into a
598 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
599 * @param bool $adj whether to adjust the time output according to the
600 * user configured offset ($timecorrection)
601 * @param mixed $format true to use user's date format preference
602 * @param string $timecorrection the time offset as returned by
603 * validateTimeZone() in Special:Preferences
604 * @return string
605 */
606 function date( $ts, $adj = false, $format = true, $timecorrection = false ) {
607 global $wgUser, $wgAmericanDates;
608
609 if ( $adj ) { $ts = $this->userAdjust( $ts, $timecorrection ); }
610
611 $datePreference = $this->dateFormat( $format );
612 if( $datePreference == MW_DATE_DEFAULT ) {
613 $datePreference = $wgAmericanDates ? MW_DATE_MDY : MW_DATE_DMY;
614 }
615
616 $month = $this->formatMonth( substr( $ts, 4, 2 ), $datePreference );
617 $day = $this->formatDay( substr( $ts, 6, 2 ), $datePreference );
618 $year = $this->formatNum( substr( $ts, 0, 4 ), true );
619
620 switch( $datePreference ) {
621 case MW_DATE_DMY: return "$day $month $year";
622 case MW_DATE_YMD: return "$year $month $day";
623 case MW_DATE_ISO: return substr($ts, 0, 4). '-' . substr($ts, 4, 2). '-' .substr($ts, 6, 2);
624 default: return "$month $day, $year";
625 }
626 }
627
628 /**
629 * @public
630 * @param mixed $ts the time format which needs to be turned into a
631 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
632 * @param bool $adj whether to adjust the time output according to the
633 * user configured offset ($timecorrection)
634 * @param mixed $format true to use user's date format preference
635 * @param string $timecorrection the time offset as returned by
636 * validateTimeZone() in Special:Preferences
637 * @return string
638 */
639 function time( $ts, $adj = false, $format = true, $timecorrection = false ) {
640 global $wgUser;
641
642 if ( $adj ) { $ts = $this->userAdjust( $ts, $timecorrection ); }
643 $datePreference = $this->dateFormat( $format );
644
645 $sep = ($datePreference == MW_DATE_ISO)
646 ? ':'
647 : $this->timeSeparator( $format );
648
649 $hh = $this->formatNum( substr( $ts, 8, 2 ), true );
650 $mm = $this->formatNum( substr( $ts, 10, 2 ), true );
651 $ss = $this->formatNum( substr( $ts, 12, 2 ), true );
652
653 $t = $hh . $sep . $mm;
654
655 if ( $datePreference == MW_DATE_ISO ) {
656 $t .= $sep . $ss;
657 }
658 return $t;
659 }
660
661 /**
662 * Default separator character between hours, minutes, and seconds.
663 * Will be used by Language::time() for non-ISO formats.
664 * (ISO will always use a colon.)
665 * @return string
666 */
667 function timeSeparator( $format ) {
668 return ':';
669 }
670
671 /**
672 * String to insert between the time and the date in a combined
673 * string. Should include any relevant whitespace.
674 * @return string
675 */
676 function timeDateSeparator( $format ) {
677 return ', ';
678 }
679
680 /**
681 * Return true if the time should display before the date.
682 * @return bool
683 * @private
684 */
685 function timeBeforeDate() {
686 return true;
687 }
688
689 function formatMonth( $month, $format ) {
690 return $this->getMonthName( $month );
691 }
692
693 function formatDay( $day, $format ) {
694 return $this->formatNum( 0 + $day, true );
695 }
696
697 /**
698 * @public
699 * @param mixed $ts the time format which needs to be turned into a
700 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
701 * @param bool $adj whether to adjust the time output according to the
702 * user configured offset ($timecorrection)
703
704 * @param mixed $format what format to return, if it's false output the
705 * default one (default true)
706 * @param string $timecorrection the time offset as returned by
707 * validateTimeZone() in Special:Preferences
708 * @return string
709 */
710 function timeanddate( $ts, $adj = false, $format = true, $timecorrection = false) {
711 global $wgUser;
712
713 $datePreference = $this->dateFormat($format);
714 switch ( $datePreference ) {
715 case MW_DATE_ISO: return $this->date( $ts, $adj, $format, $timecorrection ) . ' ' .
716 $this->time( $ts, $adj, $format, $timecorrection );
717 default:
718 $time = $this->time( $ts, $adj, $format, $timecorrection );
719 $sep = $this->timeDateSeparator( $datePreference );
720 $date = $this->date( $ts, $adj, $format, $timecorrection );
721 return $this->timeBeforeDate( $datePreference )
722 ? $time . $sep . $date
723 : $date . $sep . $time;
724 }
725 }
726
727 function getMessage( $key ) {
728 global $wgAllMessagesEn;
729 return @$wgAllMessagesEn[$key];
730 }
731
732 function getAllMessages() {
733 global $wgAllMessagesEn;
734 return $wgAllMessagesEn;
735 }
736
737 function iconv( $in, $out, $string ) {
738 # For most languages, this is a wrapper for iconv
739 return iconv( $in, $out, $string );
740 }
741
742 function ucfirst( $string ) {
743 # For most languages, this is a wrapper for ucfirst()
744 return ucfirst( $string );
745 }
746
747 function uc( $str ) {
748 return strtoupper( $str );
749 }
750
751 function lcfirst( $s ) {
752 return strtolower( $s{0} ). substr( $s, 1 );
753 }
754
755 function lc( $str ) {
756 return strtolower( $str );
757 }
758
759 function checkTitleEncoding( $s ) {
760 global $wgInputEncoding;
761
762 # Check for UTF-8 URLs; Internet Explorer produces these if you
763 # type non-ASCII chars in the URL bar or follow unescaped links.
764 $ishigh = preg_match( '/[\x80-\xff]/', $s);
765 $isutf = ($ishigh ? preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
766 '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s ) : true );
767
768 if( ($wgInputEncoding != 'utf-8') and $ishigh and $isutf )
769 return @iconv( 'UTF-8', $wgInputEncoding, $s );
770
771 if( ($wgInputEncoding == 'utf-8') and $ishigh and !$isutf )
772 return utf8_encode( $s );
773
774 # Other languages can safely leave this function, or replace
775 # it with one to detect and convert another legacy encoding.
776 return $s;
777 }
778
779 /**
780 * Some languages have special punctuation to strip out
781 * or characters which need to be converted for MySQL's
782 * indexing to grok it correctly. Make such changes here.
783 *
784 * @param string $in
785 * @return string
786 */
787 function stripForSearch( $in ) {
788 return strtolower( $in );
789 }
790
791 function convertForSearchResult( $termsArray ) {
792 # some languages, e.g. Chinese, need to do a conversion
793 # in order for search results to be displayed correctly
794 return $termsArray;
795 }
796
797 /**
798 * Get the first character of a string. In ASCII, return
799 * first byte of the string. UTF8 and others have to
800 * overload this.
801 *
802 * @param string $s
803 * @return string
804 */
805 function firstChar( $s ) {
806 return $s[0];
807 }
808
809 function initEncoding() {
810 # Some languages may have an alternate char encoding option
811 # (Esperanto X-coding, Japanese furigana conversion, etc)
812 # If this language is used as the primary content language,
813 # an override to the defaults can be set here on startup.
814 #global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
815 }
816
817 function setAltEncoding() {
818 # Some languages may have an alternate char encoding option
819 # (Esperanto X-coding, Japanese furigana conversion, etc)
820 # If 'altencoding' is checked in user prefs, this gives a
821 # chance to swap out the default encoding settings.
822 #global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
823 }
824
825 function recodeForEdit( $s ) {
826 # For some languages we'll want to explicitly specify
827 # which characters make it into the edit box raw
828 # or are converted in some way or another.
829 # Note that if wgOutputEncoding is different from
830 # wgInputEncoding, this text will be further converted
831 # to wgOutputEncoding.
832 global $wgInputEncoding, $wgEditEncoding;
833 if( $wgEditEncoding == '' or
834 $wgEditEncoding == $wgInputEncoding ) {
835 return $s;
836 } else {
837 return $this->iconv( $wgInputEncoding, $wgEditEncoding, $s );
838 }
839 }
840
841 function recodeInput( $s ) {
842 # Take the previous into account.
843 global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
844 if($wgEditEncoding != "") {
845 $enc = $wgEditEncoding;
846 } else {
847 $enc = $wgOutputEncoding;
848 }
849 if( $enc == $wgInputEncoding ) {
850 return $s;
851 } else {
852 return $this->iconv( $enc, $wgInputEncoding, $s );
853 }
854 }
855
856 /**
857 * For right-to-left language support
858 *
859 * @return bool
860 */
861 function isRTL() { return false; }
862
863 /**
864 * To allow "foo[[bar]]" to extend the link over the whole word "foobar"
865 *
866 * @return bool
867 */
868 function linkPrefixExtension() { return false; }
869
870
871 function &getMagicWords() {
872 global $wgMagicWordsEn;
873 return $wgMagicWordsEn;
874 }
875
876 # Fill a MagicWord object with data from here
877 function getMagic( &$mw ) {
878 $raw = $this->getMagicWords();
879
880 wfRunHooks( 'LanguageGetMagic', array( &$raw ) );
881
882 if( !isset( $raw[$mw->mId] ) ) {
883 # Fall back to English if local list is incomplete
884 $raw =& Language::getMagicWords();
885 }
886 $rawEntry = $raw[$mw->mId];
887 $mw->mCaseSensitive = $rawEntry[0];
888 $mw->mSynonyms = array_slice( $rawEntry, 1 );
889 }
890
891 /**
892 * Italic is unsuitable for some languages
893 *
894 * @public
895 *
896 * @param string $text The text to be emphasized.
897 * @return string
898 */
899 function emphasize( $text ) {
900 return "<em>$text</em>";
901 }
902
903 /**
904 * Normally we output all numbers in plain en_US style, that is
905 * 293,291.235 for twohundredninetythreethousand-twohundredninetyone
906 * point twohundredthirtyfive. However this is not sutable for all
907 * languages, some such as Pakaran want ੨੯੩,੨੯੫.੨੩੫ and others such as
908 * Icelandic just want to use commas instead of dots, and dots instead
909 * of commas like "293.291,235".
910 *
911 * An example of this function being called:
912 * <code>
913 * wfMsg( 'message', $wgLang->formatNum( $num ) )
914 * </code>
915 *
916 * See LanguageGu.php for the Gujarati implementation and
917 * LanguageIs.php for the , => . and . => , implementation.
918 *
919 * @todo check if it's viable to use localeconv() for the decimal
920 * seperator thing.
921 * @public
922 * @param mixed $number the string to be formatted, should be an integer or
923 * a floating point number.
924 * @param bool $nocommafy Set to true for special numbers like dates
925 * @return string
926 */
927 function formatNum( $number, $nocommafy = false ) {
928 global $wgTranslateNumerals;
929 if (!$nocommafy) {
930 $number = $this->commafy($number);
931 $s = $this->separatorTransformTable();
932 if (!is_null($s)) { $number = strtr($number, $s); }
933 }
934
935 if ($wgTranslateNumerals) {
936 $s = $this->digitTransformTable();
937 if (!is_null($s)) { $number = strtr($number, $s); }
938 }
939
940 return $number;
941 }
942
943 /**
944 * Adds commas to a given number
945 *
946 * @param mixed $_
947 * @return string
948 */
949 function commafy($_) {
950 return strrev((string)preg_replace('/(\d{3})(?=\d)(?!\d*\.)/','$1,',strrev($_)));
951 }
952
953 function digitTransformTable() {
954 return null;
955 }
956
957 function separatorTransformTable() {
958 return null;
959 }
960
961
962 /**
963 * For the credit list in includes/Credits.php (action=credits)
964 *
965 * @param array $l
966 * @return string
967 */
968 function listToText( $l ) {
969 $s = '';
970 $m = count($l) - 1;
971 for ($i = $m; $i >= 0; $i--) {
972 if ($i == $m) {
973 $s = $l[$i];
974 } else if ($i == $m - 1) {
975 $s = $l[$i] . ' ' . wfMsg('and') . ' ' . $s;
976 } else {
977 $s = $l[$i] . ', ' . $s;
978 }
979 }
980 return $s;
981 }
982
983 # Crop a string from the beginning or end to a certain number of bytes.
984 # (Bytes are used because our storage has limited byte lengths for some
985 # columns in the database.) Multibyte charsets will need to make sure that
986 # only whole characters are included!
987 #
988 # $length does not include the optional ellipsis.
989 # If $length is negative, snip from the beginning
990 function truncate( $string, $length, $ellipsis = '' ) {
991 if( $length == 0 ) {
992 return $ellipsis;
993 }
994 if ( strlen( $string ) <= abs( $length ) ) {
995 return $string;
996 }
997 if( $length > 0 ) {
998 $string = substr( $string, 0, $length );
999 return $string . $ellipsis;
1000 } else {
1001 $string = substr( $string, $length );
1002 return $ellipsis . $string;
1003 }
1004 }
1005
1006 /**
1007 * Grammatical transformations, needed for inflected languages
1008 * Invoked by putting {{grammar:case|word}} in a message
1009 *
1010 * @param string $word
1011 * @param string $case
1012 * @return string
1013 */
1014 function convertGrammar( $word, $case ) {
1015 return $word;
1016 }
1017
1018 /**
1019 * Plural form transformations, needed for some languages.
1020 * For example, where are 3 form of plural in Russian and Polish,
1021 * depending on "count mod 10". See [[w:Plural]]
1022 * For English it is pretty simple.
1023 *
1024 * Invoked by putting {{plural:count|wordform1|wordform2}}
1025 * or {{plural:count|wordform1|wordform2|wordform3}}
1026 *
1027 * Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}}
1028 *
1029 * @param integer $count
1030 * @param string $wordform1
1031 * @param string $wordform2
1032 * @param string $wordform3 (optional)
1033 * @return string
1034 */
1035 function convertPlural( $count, $wordform1, $wordform2, $wordform3) {
1036 return $count == '1' ? $wordform1 : $wordform2;
1037 }
1038
1039 /**
1040 * For translaing of expiry times
1041 * @param string The validated block time in English
1042 * @return Somehow translated block time
1043 * @see LanguageFi.php for example implementation
1044 */
1045 function translateBlockExpiry( $str ) {
1046
1047 $scBlockExpiryOptions = wfMsg( 'ipboptions' );
1048
1049 if ( $scBlockExpiryOptions == '-') {
1050 return $str;
1051 }
1052
1053 foreach (explode(',', $scBlockExpiryOptions) as $option) {
1054 if ( strpos($option, ":") === false )
1055 continue;
1056 list($show, $value) = explode(":", $option);
1057 if ( strcmp ( $str, $value) == 0 )
1058 return '<span title="' . htmlspecialchars($str). '">' .
1059 htmlspecialchars( trim( $show ) ) . '</span>';
1060 }
1061
1062 return $str;
1063 }
1064
1065 /**
1066 * languages like Chinese need to be segmented in order for the diff
1067 * to be of any use
1068 *
1069 * @param string $text
1070 * @return string
1071 */
1072 function segmentForDiff( $text ) {
1073 return $text;
1074 }
1075
1076 /**
1077 * and unsegment to show the result
1078 *
1079 * @param string $text
1080 * @return string
1081 */
1082 function unsegmentForDiff( $text ) {
1083 return $text;
1084 }
1085
1086 # convert text to different variants of a language.
1087 function convert( $text, $isTitle = false) {
1088 return $this->mConverter->convert($text, $isTitle);
1089 }
1090
1091 # Convert text from within Parser
1092 function parserConvert( $text, &$parser ) {
1093 return $this->mConverter->parserConvert( $text, $parser );
1094 }
1095
1096 /**
1097 * Perform output conversion on a string, and encode for safe HTML output.
1098 * @param string $text
1099 * @param bool $isTitle -- wtf?
1100 * @return string
1101 * @todo this should get integrated somewhere sane
1102 */
1103 function convertHtml( $text, $isTitle = false ) {
1104 return htmlspecialchars( $this->convert( $text, $isTitle ) );
1105 }
1106
1107 function convertCategoryKey( $key ) {
1108 return $this->mConverter->convertCategoryKey( $key );
1109 }
1110
1111 /**
1112 * get the list of variants supported by this langauge
1113 * see sample implementation in LanguageZh.php
1114 *
1115 * @return array an array of language codes
1116 */
1117 function getVariants() {
1118 return $this->mConverter->getVariants();
1119 }
1120
1121
1122 function getPreferredVariant() {
1123 return $this->mConverter->getPreferredVariant();
1124 }
1125
1126 /**
1127 * if a language supports multiple variants, it is
1128 * possible that non-existing link in one variant
1129 * actually exists in another variant. this function
1130 * tries to find it. See e.g. LanguageZh.php
1131 *
1132 * @param string $link the name of the link
1133 * @param mixed $nt the title object of the link
1134 * @return null the input parameters may be modified upon return
1135 */
1136 function findVariantLink( &$link, &$nt ) {
1137 $this->mConverter->findVariantLink($link, $nt);
1138 }
1139
1140 /**
1141 * returns language specific options used by User::getPageRenderHash()
1142 * for example, the preferred language variant
1143 *
1144 * @return string
1145 * @public
1146 */
1147 function getExtraHashOptions() {
1148 return $this->mConverter->getExtraHashOptions();
1149 }
1150
1151 /**
1152 * for languages that support multiple variants, the title of an
1153 * article may be displayed differently in different variants. this
1154 * function returns the apporiate title defined in the body of the article.
1155 *
1156 * @return string
1157 */
1158 function getParsedTitle() {
1159 return $this->mConverter->getParsedTitle();
1160 }
1161
1162 /**
1163 * Enclose a string with the "no conversion" tag. This is used by
1164 * various functions in the Parser
1165 *
1166 * @param string $text text to be tagged for no conversion
1167 * @return string the tagged text
1168 */
1169 function markNoConversion( $text ) {
1170 return $this->mConverter->markNoConversion( $text );
1171 }
1172
1173 /**
1174 * A regular expression to match legal word-trailing characters
1175 * which should be merged onto a link of the form [[foo]]bar.
1176 *
1177 * @return string
1178 * @public
1179 */
1180 function linkTrail() {
1181 return $this->getMessage( 'linktrail' );
1182 }
1183
1184 function getLangObj() {
1185 return $this;
1186 }
1187
1188 /**
1189 * Get the RFC 3066 code for this language object
1190 */
1191 function getCode() {
1192 return str_replace( '_', '-', strtolower( substr( get_class( $this ), 8 ) ) );
1193 }
1194
1195
1196 }
1197
1198 # FIXME: Merge all UTF-8 support code into Language base class.
1199 # We no longer support Latin-1 charset.
1200 require_once( 'LanguageUtf8.php' );
1201
1202 # This should fail gracefully if there's not a localization available
1203 wfSuppressWarnings();
1204 // Preload base classes to work around APC/PHP5 bug
1205 include_once( 'Language' . str_replace( '-', '_', ucfirst( $wgLanguageCode ) ) . '.deps.php' );
1206 include_once( 'Language' . str_replace( '-', '_', ucfirst( $wgLanguageCode ) ) . '.php' );
1207 wfRestoreWarnings();
1208
1209 }
1210 ?>