Enable UTF-8 lower/upper case operations in SearchEngine,
[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 'redirect' => array( 0, '#REDIRECT' ),
215 'notoc' => array( 0, '__NOTOC__' ),
216 'nogallery' => array( 0, '__NOGALLERY__' ),
217 'forcetoc' => array( 0, '__FORCETOC__' ),
218 'toc' => array( 0, '__TOC__' ),
219 'noeditsection' => array( 0, '__NOEDITSECTION__' ),
220 'start' => array( 0, '__START__' ),
221 'currentmonth' => array( 1, 'CURRENTMONTH' ),
222 'currentmonthname' => array( 1, 'CURRENTMONTHNAME' ),
223 'currentmonthnamegen' => array( 1, 'CURRENTMONTHNAMEGEN' ),
224 'currentmonthabbrev' => array( 1, 'CURRENTMONTHABBREV' ),
225 'currentday' => array( 1, 'CURRENTDAY' ),
226 'currentday2' => array( 1, 'CURRENTDAY2' ),
227 'currentdayname' => array( 1, 'CURRENTDAYNAME' ),
228 'currentyear' => array( 1, 'CURRENTYEAR' ),
229 'currenttime' => array( 1, 'CURRENTTIME' ),
230 'numberofpages' => array( 1, 'NUMBEROFPAGES' ),
231 'numberofarticles' => array( 1, 'NUMBEROFARTICLES' ),
232 'numberoffiles' => array( 1, 'NUMBEROFFILES' ),
233 'numberofusers' => array( 1, 'NUMBEROFUSERS' ),
234 'pagename' => array( 1, 'PAGENAME' ),
235 'pagenamee' => array( 1, 'PAGENAMEE' ),
236 'namespace' => array( 1, 'NAMESPACE' ),
237 'namespacee' => array( 1, 'NAMESPACEE' ),
238 'talkspace' => array( 1, 'TALKSPACE' ),
239 'talkspacee' => array( 1, 'TALKSPACEE' ),
240 'subjectspace' => array( 1, 'SUBJECTSPACE', 'ARTICLESPACE' ),
241 'subjectspacee' => array( 1, 'SUBJECTSPACEE', 'ARTICLESPACEE' ),
242 'fullpagename' => array( 1, 'FULLPAGENAME' ),
243 'fullpagenamee' => array( 1, 'FULLPAGENAMEE' ),
244 'subpagename' => array( 1, 'SUBPAGENAME' ),
245 'subpagenamee' => array( 1, 'SUBPAGENAMEE' ),
246 'basepagename' => array( 1, 'BASEPAGENAME' ),
247 'basepagenamee' => array( 1, 'BASEPAGENAMEE' ),
248 'talkpagename' => array( 1, 'TALKPAGENAME' ),
249 'talkpagenamee' => array( 1, 'TALKPAGENAMEE' ),
250 'subjectpagename' => array( 1, 'SUBJECTPAGENAME', 'ARTICLEPAGENAME' ),
251 'subjectpagenamee' => array( 1, 'SUBJECTPAGENAMEE', 'ARTICLEPAGENAMEE' ),
252 'msg' => array( 0, 'MSG:' ),
253 'subst' => array( 0, 'SUBST:' ),
254 'msgnw' => array( 0, 'MSGNW:' ),
255 'end' => array( 0, '__END__' ),
256 'img_thumbnail' => array( 1, 'thumbnail', 'thumb' ),
257 'img_manualthumb' => array( 1, 'thumbnail=$1', 'thumb=$1'),
258 'img_right' => array( 1, 'right' ),
259 'img_left' => array( 1, 'left' ),
260 'img_none' => array( 1, 'none' ),
261 'img_width' => array( 1, '$1px' ),
262 'img_center' => array( 1, 'center', 'centre' ),
263 'img_framed' => array( 1, 'framed', 'enframed', 'frame' ),
264 'int' => array( 0, 'INT:' ),
265 'sitename' => array( 1, 'SITENAME' ),
266 'ns' => array( 0, 'NS:' ),
267 'localurl' => array( 0, 'LOCALURL:' ),
268 'localurle' => array( 0, 'LOCALURLE:' ),
269 'server' => array( 0, 'SERVER' ),
270 'servername' => array( 0, 'SERVERNAME' ),
271 'scriptpath' => array( 0, 'SCRIPTPATH' ),
272 'grammar' => array( 0, 'GRAMMAR:' ),
273 'notitleconvert' => array( 0, '__NOTITLECONVERT__', '__NOTC__'),
274 'nocontentconvert' => array( 0, '__NOCONTENTCONVERT__', '__NOCC__'),
275 'currentweek' => array( 1, 'CURRENTWEEK' ),
276 'currentdow' => array( 1, 'CURRENTDOW' ),
277 'revisionid' => array( 1, 'REVISIONID' ),
278 'plural' => array( 0, 'PLURAL:' ),
279 'fullurl' => array( 0, 'FULLURL:' ),
280 'fullurle' => array( 0, 'FULLURLE:' ),
281 'lcfirst' => array( 0, 'LCFIRST:' ),
282 'ucfirst' => array( 0, 'UCFIRST:' ),
283 'lc' => array( 0, 'LC:' ),
284 'uc' => array( 0, 'UC:' ),
285 'raw' => array( 0, 'RAW:' ),
286 'displaytitle' => array( 1, 'DISPLAYTITLE' ),
287 'rawsuffix' => array( 1, 'R' ),
288 'newsectionlink' => array( 1, '__NEWSECTIONLINK__' ),
289 'currentversion' => array( 1, 'CURRENTVERSION' ),
290 'urlencode' => array( 0, 'URLENCODE:' ),
291 'currenttimestamp' => array( 1, 'CURRENTTIMESTAMP' ),
292 'directionmark' => array( 1, 'DIRECTIONMARK', 'DIRMARK' ),
293 'language' => array( 0, '#LANGUAGE:' ),
294 'contentlanguage' => array( 1, 'CONTENTLANGUAGE', 'CONTENTLANG' ),
295 'pagesinnamespace' => array( 1, 'PAGESINNAMESPACE:', 'PAGESINNS:' ),
296 'numberofadmins' => array( 1, 'NUMBEROFADMINS' ),
297 'formatnum' => array( 0, 'FORMATNUM' ),
298
299 );
300
301 if (!$wgCachedMessageArrays) {
302 require_once('Messages.php');
303 }
304
305 /* a fake language converter */
306 class fakeConverter {
307 var $mLang;
308 function fakeConverter($langobj) {$this->mLang = $langobj;}
309 function convert($t, $i) {return $t;}
310 function parserConvert($t, $p) {return $t;}
311 function getVariants() { return array( $this->mLang->getCode() ); }
312 function getPreferredVariant() {return $this->mLang->getCode(); }
313 function findVariantLink(&$l, &$n) {}
314 function getExtraHashOptions() {return '';}
315 function getParsedTitle() {return '';}
316 function markNoConversion($text) {return $text;}
317 function convertCategoryKey( $key ) {return $key; }
318 function convertLinkToAllVariants($text){ return array( $this->mLang->getCode() => $text); }
319
320 }
321
322 #--------------------------------------------------------------------------
323 # Internationalisation code
324 #--------------------------------------------------------------------------
325
326 class Language {
327 var $mConverter;
328 function __construct() {
329 $this->mConverter = new fakeConverter($this);
330 }
331
332 /**
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.
336 *
337 * @return array
338 */
339 function getDefaultUserOptions() {
340 global $wgDefaultUserOptionsEn;
341 return $wgDefaultUserOptionsEn;
342 }
343
344 /**
345 * Exports $wgBookstoreListEn
346 * @return array
347 */
348 function getBookstoreList() {
349 global $wgBookstoreListEn;
350 return $wgBookstoreListEn;
351 }
352
353 /**
354 * @return array
355 */
356 function getNamespaces() {
357 global $wgNamespaceNamesEn;
358 return $wgNamespaceNamesEn;
359 }
360
361 /**
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.
366 *
367 * @return array
368 */
369 function getFormattedNamespaces() {
370 $ns = $this->getNamespaces();
371 foreach($ns as $k => $v) {
372 $ns[$k] = strtr($v, '_', ' ');
373 }
374 return $ns;
375 }
376
377 /**
378 * Get a namespace value by key
379 * <code>
380 * $mw_ns = $wgContLang->getNsText( NS_MEDIAWIKI );
381 * echo $mw_ns; // prints 'MediaWiki'
382 * </code>
383 *
384 * @param int $index the array key of the namespace to return
385 * @return mixed, string if the namespace value exists, otherwise false
386 */
387 function getNsText( $index ) {
388 $ns = $this->getNamespaces();
389 return isset( $ns[$index] ) ? $ns[$index] : false;
390 }
391
392 /**
393 * A convenience function that returns the same thing as
394 * getNsText() except with '_' changed to ' ', useful for
395 * producing output.
396 *
397 * @return array
398 */
399 function getFormattedNsText( $index ) {
400 $ns = $this->getNsText( $index );
401 return strtr($ns, '_', ' ');
402 }
403
404 /**
405 * Get a namespace key by value, case insensetive.
406 *
407 * @param string $text
408 * @return mixed An integer if $text is a valid value otherwise false
409 */
410 function getNsIndex( $text ) {
411 $ns = $this->getNamespaces();
412
413 foreach ( $ns as $i => $n ) {
414 if ( strcasecmp( $n, $text ) == 0)
415 return $i;
416 }
417 return false;
418 }
419
420 /**
421 * short names for language variants used for language conversion links.
422 *
423 * @param string $code
424 * @return string
425 */
426 function getVariantname( $code ) {
427 return wfMsg( "variantname-$code" );
428 }
429
430 function specialPage( $name ) {
431 return $this->getNsText(NS_SPECIAL) . ':' . $name;
432 }
433
434 function getQuickbarSettings() {
435 global $wgQuickbarSettingsEn;
436 return $wgQuickbarSettingsEn;
437 }
438
439 function getSkinNames() {
440 global $wgSkinNamesEn;
441 return $wgSkinNamesEn;
442 }
443
444 function getMathNames() {
445 global $wgMathNamesEn;
446 return $wgMathNamesEn;
447 }
448
449 function getDateFormats() {
450 global $wgDateFormatsEn;
451 return $wgDateFormatsEn;
452 }
453
454 function getUserToggles() {
455 global $wgUserTogglesEn;
456 return $wgUserTogglesEn;
457 }
458
459 function getUserToggle( $tog ) {
460 return wfMsg( "tog-$tog" );
461 }
462
463 function getLanguageNames() {
464 global $wgLanguageNamesEn;
465 return $wgLanguageNamesEn;
466 }
467
468 function getLanguageName( $code ) {
469 global $wgLanguageNamesEn;
470 if ( ! array_key_exists( $code, $wgLanguageNamesEn ) ) {
471 return '';
472 }
473 return $wgLanguageNamesEn[$code];
474 }
475
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]);
483 }
484
485 /* by default we just return base form */
486 function getMonthNameGen( $key ) {
487 return $this->getMonthName( $key );
488 }
489
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]);
497 }
498
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]);
506 }
507
508 /**
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
515
516 */
517 function userAdjust( $ts, $tz = false ) {
518 global $wgUser, $wgLocalTZoffset;
519
520 if (!$tz) {
521 $tz = $wgUser->getOption( 'timecorrection' );
522 }
523
524 # minutes and hours differences:
525 $minDiff = 0;
526 $hrDiff = 0;
527
528 if ( $tz === '' ) {
529 # Global offset in minutes.
530 if( isset($wgLocalTZoffset) ) {
531 $hrDiff = $wgLocalTZoffset % 60;
532 $minDiff = $wgLocalTZoffset - ($hrDiff * 60);
533 }
534 } elseif ( strpos( $tz, ':' ) !== false ) {
535 $tzArray = explode( ':', $tz );
536 $hrDiff = intval($tzArray[0]);
537 $minDiff = intval($hrDiff < 0 ? -$tzArray[1] : $tzArray[1]);
538 } else {
539 $hrDiff = intval( $tz );
540 }
541
542 # No difference ? Return time unchanged
543 if ( 0 == $hrDiff && 0 == $minDiff ) { return $ts; }
544
545 # Generate an adjusted date
546 $t = mktime( (
547 (int)substr( $ts, 8, 2) ) + $hrDiff, # Hours
548 (int)substr( $ts, 10, 2 ) + $minDiff, # Minutes
549 (int)substr( $ts, 12, 2 ), # Seconds
550 (int)substr( $ts, 4, 2 ), # Month
551 (int)substr( $ts, 6, 2 ), # Day
552 (int)substr( $ts, 0, 4 ) ); #Year
553 return date( 'YmdHis', $t );
554 }
555
556 /**
557 * This is meant to be used by time(), date(), and timeanddate() to get
558 * the date preference they're supposed to use, it should be used in
559 * all children.
560 *
561 *<code>
562 * function timeanddate([...], $format = true) {
563 * $datePreference = $this->dateFormat($format);
564 * [...]
565 *</code>
566 *
567 * @param mixed $usePrefs: if true, the user's preference is used
568 * if false, the site/language default is used
569 * if int/string, assumed to be a format.
570 * @return string
571 */
572 function dateFormat( $usePrefs = true ) {
573 global $wgUser;
574
575 if( is_bool( $usePrefs ) ) {
576 if( $usePrefs ) {
577 $datePreference = $wgUser->getOption( 'date' );
578 } else {
579 $options = $this->getDefaultUserOptions();
580 $datePreference = (string)$options['date'];
581 }
582 } else {
583 $datePreference = (string)$usePrefs;
584 }
585
586 // return int
587 if( $datePreference == '' ) {
588 return MW_DATE_DEFAULT;
589 }
590
591 return $datePreference;
592 }
593
594 /**
595 * @public
596 * @param mixed $ts the time format which needs to be turned into a
597 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
598 * @param bool $adj whether to adjust the time output according to the
599 * user configured offset ($timecorrection)
600 * @param mixed $format true to use user's date format preference
601 * @param string $timecorrection the time offset as returned by
602 * validateTimeZone() in Special:Preferences
603 * @return string
604 */
605 function date( $ts, $adj = false, $format = true, $timecorrection = false ) {
606 global $wgUser, $wgAmericanDates;
607
608 if ( $adj ) { $ts = $this->userAdjust( $ts, $timecorrection ); }
609
610 $datePreference = $this->dateFormat( $format );
611 if( $datePreference == MW_DATE_DEFAULT ) {
612 $datePreference = $wgAmericanDates ? MW_DATE_MDY : MW_DATE_DMY;
613 }
614
615 $month = $this->formatMonth( substr( $ts, 4, 2 ), $datePreference );
616 $day = $this->formatDay( substr( $ts, 6, 2 ), $datePreference );
617 $year = $this->formatNum( substr( $ts, 0, 4 ), true );
618
619 switch( $datePreference ) {
620 case MW_DATE_DMY: return "$day $month $year";
621 case MW_DATE_YMD: return "$year $month $day";
622 case MW_DATE_ISO: return substr($ts, 0, 4). '-' . substr($ts, 4, 2). '-' .substr($ts, 6, 2);
623 default: return "$month $day, $year";
624 }
625 }
626
627 /**
628 * @public
629 * @param mixed $ts the time format which needs to be turned into a
630 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
631 * @param bool $adj whether to adjust the time output according to the
632 * user configured offset ($timecorrection)
633 * @param mixed $format true to use user's date format preference
634 * @param string $timecorrection the time offset as returned by
635 * validateTimeZone() in Special:Preferences
636 * @return string
637 */
638 function time( $ts, $adj = false, $format = true, $timecorrection = false ) {
639 global $wgUser;
640
641 if ( $adj ) { $ts = $this->userAdjust( $ts, $timecorrection ); }
642 $datePreference = $this->dateFormat( $format );
643
644 $sep = $this->timeSeparator( $format );
645
646 $hh = substr( $ts, 8, 2 );
647 $mm = substr( $ts, 10, 2 );
648 $ss = substr( $ts, 12, 2 );
649
650 if ( $datePreference != MW_DATE_ISO ) {
651 $hh = $this->formatNum( $hh, true );
652 $mm = $this->formatNum( $mm, true );
653 //$ss = $this->formatNum( $ss, true );
654 return $hh . $sep . $mm;
655 } else {
656 return $hh . ':' . $mm . ':' . $ss;
657 }
658 }
659
660 /**
661 * Default separator character between hours, minutes, and seconds.
662 * Will be used by Language::time() for non-ISO formats.
663 * (ISO will always use a colon.)
664 * @return string
665 */
666 function timeSeparator( $format ) {
667 return ':';
668 }
669
670 /**
671 * String to insert between the time and the date in a combined
672 * string. Should include any relevant whitespace.
673 * @return string
674 */
675 function timeDateSeparator( $format ) {
676 return ', ';
677 }
678
679 /**
680 * Return true if the time should display before the date.
681 * @return bool
682 * @private
683 */
684 function timeBeforeDate() {
685 return true;
686 }
687
688 function formatMonth( $month, $format ) {
689 return $this->getMonthName( $month );
690 }
691
692 function formatDay( $day, $format ) {
693 return $this->formatNum( 0 + $day, true );
694 }
695
696 /**
697 * @public
698 * @param mixed $ts the time format which needs to be turned into a
699 * date('YmdHis') format with wfTimestamp(TS_MW,$ts)
700 * @param bool $adj whether to adjust the time output according to the
701 * user configured offset ($timecorrection)
702
703 * @param mixed $format what format to return, if it's false output the
704 * default one (default true)
705 * @param string $timecorrection the time offset as returned by
706 * validateTimeZone() in Special:Preferences
707 * @return string
708 */
709 function timeanddate( $ts, $adj = false, $format = true, $timecorrection = false) {
710 global $wgUser;
711
712 $datePreference = $this->dateFormat($format);
713 switch ( $datePreference ) {
714 case MW_DATE_ISO: return $this->date( $ts, $adj, $format, $timecorrection ) . ' ' .
715 $this->time( $ts, $adj, $format, $timecorrection );
716 default:
717 $time = $this->time( $ts, $adj, $format, $timecorrection );
718 $sep = $this->timeDateSeparator( $datePreference );
719 $date = $this->date( $ts, $adj, $format, $timecorrection );
720 return $this->timeBeforeDate( $datePreference )
721 ? $time . $sep . $date
722 : $date . $sep . $time;
723 }
724 }
725
726 function getMessage( $key ) {
727 global $wgAllMessagesEn;
728 return @$wgAllMessagesEn[$key];
729 }
730
731 function getAllMessages() {
732 global $wgAllMessagesEn;
733 return $wgAllMessagesEn;
734 }
735
736 function iconv( $in, $out, $string ) {
737 # For most languages, this is a wrapper for iconv
738 return iconv( $in, $out, $string );
739 }
740
741 function ucfirst( $string ) {
742 # For most languages, this is a wrapper for ucfirst()
743 return ucfirst( $string );
744 }
745
746 function uc( $str ) {
747 return strtoupper( $str );
748 }
749
750 function lcfirst( $s ) {
751 return strtolower( $s{0} ). substr( $s, 1 );
752 }
753
754 function lc( $str ) {
755 return strtolower( $str );
756 }
757
758 function ucwords($str) {
759 return ucwords( strtolower( $str ) );
760 }
761
762 # capitalize words at word breaks
763 function ucwordbreaks($str){
764 return preg_replace_callback(
765 '/\b([\w\x80-\xff]+)\b/',
766 create_function( '$matches', '
767 global $wgContLang;
768 return $wgContLang->ucfirst($matches[1]);
769 ' ),
770 $str );
771 }
772
773 function checkTitleEncoding( $s ) {
774 global $wgInputEncoding;
775
776 # Check for UTF-8 URLs; Internet Explorer produces these if you
777 # type non-ASCII chars in the URL bar or follow unescaped links.
778 $ishigh = preg_match( '/[\x80-\xff]/', $s);
779 $isutf = ($ishigh ? preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
780 '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s ) : true );
781
782 if( ($wgInputEncoding != 'utf-8') and $ishigh and $isutf )
783 return @iconv( 'UTF-8', $wgInputEncoding, $s );
784
785 if( ($wgInputEncoding == 'utf-8') and $ishigh and !$isutf )
786 return utf8_encode( $s );
787
788 # Other languages can safely leave this function, or replace
789 # it with one to detect and convert another legacy encoding.
790 return $s;
791 }
792
793 /**
794 * Some languages have special punctuation to strip out
795 * or characters which need to be converted for MySQL's
796 * indexing to grok it correctly. Make such changes here.
797 *
798 * @param string $in
799 * @return string
800 */
801 function stripForSearch( $in ) {
802 return strtolower( $in );
803 }
804
805 function convertForSearchResult( $termsArray ) {
806 # some languages, e.g. Chinese, need to do a conversion
807 # in order for search results to be displayed correctly
808 return $termsArray;
809 }
810
811 /**
812 * Get the first character of a string. In ASCII, return
813 * first byte of the string. UTF8 and others have to
814 * overload this.
815 *
816 * @param string $s
817 * @return string
818 */
819 function firstChar( $s ) {
820 return $s[0];
821 }
822
823 function initEncoding() {
824 # Some languages may have an alternate char encoding option
825 # (Esperanto X-coding, Japanese furigana conversion, etc)
826 # If this language is used as the primary content language,
827 # an override to the defaults can be set here on startup.
828 #global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
829 }
830
831 function setAltEncoding() {
832 # Some languages may have an alternate char encoding option
833 # (Esperanto X-coding, Japanese furigana conversion, etc)
834 # If 'altencoding' is checked in user prefs, this gives a
835 # chance to swap out the default encoding settings.
836 #global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
837 }
838
839 function recodeForEdit( $s ) {
840 # For some languages we'll want to explicitly specify
841 # which characters make it into the edit box raw
842 # or are converted in some way or another.
843 # Note that if wgOutputEncoding is different from
844 # wgInputEncoding, this text will be further converted
845 # to wgOutputEncoding.
846 global $wgInputEncoding, $wgEditEncoding;
847 if( $wgEditEncoding == '' or
848 $wgEditEncoding == $wgInputEncoding ) {
849 return $s;
850 } else {
851 return $this->iconv( $wgInputEncoding, $wgEditEncoding, $s );
852 }
853 }
854
855 function recodeInput( $s ) {
856 # Take the previous into account.
857 global $wgInputEncoding, $wgOutputEncoding, $wgEditEncoding;
858 if($wgEditEncoding != "") {
859 $enc = $wgEditEncoding;
860 } else {
861 $enc = $wgOutputEncoding;
862 }
863 if( $enc == $wgInputEncoding ) {
864 return $s;
865 } else {
866 return $this->iconv( $enc, $wgInputEncoding, $s );
867 }
868 }
869
870 /**
871 * For right-to-left language support
872 *
873 * @return bool
874 */
875 function isRTL() { return false; }
876
877 /**
878 * A hidden direction mark (LRM or RLM), depending on the language direction
879 *
880 * @return string
881 */
882 function getDirMark() { return $this->isRTL() ? "\xE2\x80\x8F" : "\xE2\x80\x8E"; }
883
884 /**
885 * To allow "foo[[bar]]" to extend the link over the whole word "foobar"
886 *
887 * @return bool
888 */
889 function linkPrefixExtension() { return false; }
890
891 function &getMagicWords() {
892 global $wgMagicWordsEn;
893 return $wgMagicWordsEn;
894 }
895
896 # Fill a MagicWord object with data from here
897 function getMagic( &$mw ) {
898 if ( !isset( $this->mMagicExtensions ) ) {
899 $this->mMagicExtensions = array();
900 wfRunHooks( 'LanguageGetMagic', array( &$this->mMagicExtensions, $this->getCode() ) );
901 }
902 if ( isset( $this->mMagicExtensions[$mw->mId] ) ) {
903 $rawEntry = $this->mMagicExtensions[$mw->mId];
904 } else {
905 $magicWords =& $this->getMagicWords();
906 if ( isset( $magicWords[$mw->mId] ) ) {
907 $rawEntry = $magicWords[$mw->mId];
908 } else {
909 # Fall back to English if local list is incomplete
910 $magicWords =& Language::getMagicWords();
911 $rawEntry = $magicWords[$mw->mId];
912 }
913 }
914
915 $mw->mCaseSensitive = $rawEntry[0];
916 $mw->mSynonyms = array_slice( $rawEntry, 1 );
917 }
918
919 /**
920 * Italic is unsuitable for some languages
921 *
922 * @public
923 *
924 * @param string $text The text to be emphasized.
925 * @return string
926 */
927 function emphasize( $text ) {
928 return "<em>$text</em>";
929 }
930
931 /**
932 * Normally we output all numbers in plain en_US style, that is
933 * 293,291.235 for twohundredninetythreethousand-twohundredninetyone
934 * point twohundredthirtyfive. However this is not sutable for all
935 * languages, some such as Pakaran want ੨੯੩,੨੯੫.੨੩੫ and others such as
936 * Icelandic just want to use commas instead of dots, and dots instead
937 * of commas like "293.291,235".
938 *
939 * An example of this function being called:
940 * <code>
941 * wfMsg( 'message', $wgLang->formatNum( $num ) )
942 * </code>
943 *
944 * See LanguageGu.php for the Gujarati implementation and
945 * LanguageIs.php for the , => . and . => , implementation.
946 *
947 * @todo check if it's viable to use localeconv() for the decimal
948 * seperator thing.
949 * @public
950 * @param mixed $number the string to be formatted, should be an integer or
951 * a floating point number.
952 * @param bool $nocommafy Set to true for special numbers like dates
953 * @return string
954 */
955 function formatNum( $number, $nocommafy = false ) {
956 global $wgTranslateNumerals;
957 if (!$nocommafy) {
958 $number = $this->commafy($number);
959 $s = $this->separatorTransformTable();
960 if (!is_null($s)) { $number = strtr($number, $s); }
961 }
962
963 if ($wgTranslateNumerals) {
964 $s = $this->digitTransformTable();
965 if (!is_null($s)) { $number = strtr($number, $s); }
966 }
967
968 return $number;
969 }
970
971 /**
972 * Adds commas to a given number
973 *
974 * @param mixed $_
975 * @return string
976 */
977 function commafy($_) {
978 return strrev((string)preg_replace('/(\d{3})(?=\d)(?!\d*\.)/','$1,',strrev($_)));
979 }
980
981 function digitTransformTable() {
982 return null;
983 }
984
985 function separatorTransformTable() {
986 return null;
987 }
988
989
990 /**
991 * For the credit list in includes/Credits.php (action=credits)
992 *
993 * @param array $l
994 * @return string
995 */
996 function listToText( $l ) {
997 $s = '';
998 $m = count($l) - 1;
999 for ($i = $m; $i >= 0; $i--) {
1000 if ($i == $m) {
1001 $s = $l[$i];
1002 } else if ($i == $m - 1) {
1003 $s = $l[$i] . ' ' . wfMsg('and') . ' ' . $s;
1004 } else {
1005 $s = $l[$i] . ', ' . $s;
1006 }
1007 }
1008 return $s;
1009 }
1010
1011 # Crop a string from the beginning or end to a certain number of bytes.
1012 # (Bytes are used because our storage has limited byte lengths for some
1013 # columns in the database.) Multibyte charsets will need to make sure that
1014 # only whole characters are included!
1015 #
1016 # $length does not include the optional ellipsis.
1017 # If $length is negative, snip from the beginning
1018 function truncate( $string, $length, $ellipsis = '' ) {
1019 if( $length == 0 ) {
1020 return $ellipsis;
1021 }
1022 if ( strlen( $string ) <= abs( $length ) ) {
1023 return $string;
1024 }
1025 if( $length > 0 ) {
1026 $string = substr( $string, 0, $length );
1027 return $string . $ellipsis;
1028 } else {
1029 $string = substr( $string, $length );
1030 return $ellipsis . $string;
1031 }
1032 }
1033
1034 /**
1035 * Grammatical transformations, needed for inflected languages
1036 * Invoked by putting {{grammar:case|word}} in a message
1037 *
1038 * @param string $word
1039 * @param string $case
1040 * @return string
1041 */
1042 function convertGrammar( $word, $case ) {
1043 global $wgGrammarForms;
1044 if ( isset($wgGrammarForms['en'][$case][$word]) ) {
1045 return $wgGrammarForms['en'][$case][$word];
1046 }
1047 return $word;
1048 }
1049
1050 /**
1051 * Plural form transformations, needed for some languages.
1052 * For example, where are 3 form of plural in Russian and Polish,
1053 * depending on "count mod 10". See [[w:Plural]]
1054 * For English it is pretty simple.
1055 *
1056 * Invoked by putting {{plural:count|wordform1|wordform2}}
1057 * or {{plural:count|wordform1|wordform2|wordform3}}
1058 *
1059 * Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}}
1060 *
1061 * @param integer $count
1062 * @param string $wordform1
1063 * @param string $wordform2
1064 * @param string $wordform3 (optional)
1065 * @return string
1066 */
1067 function convertPlural( $count, $w1, $w2, $w3) {
1068 return $count == '1' ? $w1 : $w2;
1069 }
1070
1071 /**
1072 * For translaing of expiry times
1073 * @param string The validated block time in English
1074 * @return Somehow translated block time
1075 * @see LanguageFi.php for example implementation
1076 */
1077 function translateBlockExpiry( $str ) {
1078
1079 $scBlockExpiryOptions = wfMsg( 'ipboptions' );
1080
1081 if ( $scBlockExpiryOptions == '-') {
1082 return $str;
1083 }
1084
1085 foreach (explode(',', $scBlockExpiryOptions) as $option) {
1086 if ( strpos($option, ":") === false )
1087 continue;
1088 list($show, $value) = explode(":", $option);
1089 if ( strcmp ( $str, $value) == 0 )
1090 return '<span title="' . htmlspecialchars($str). '">' .
1091 htmlspecialchars( trim( $show ) ) . '</span>';
1092 }
1093
1094 return $str;
1095 }
1096
1097 /**
1098 * languages like Chinese need to be segmented in order for the diff
1099 * to be of any use
1100 *
1101 * @param string $text
1102 * @return string
1103 */
1104 function segmentForDiff( $text ) {
1105 return $text;
1106 }
1107
1108 /**
1109 * and unsegment to show the result
1110 *
1111 * @param string $text
1112 * @return string
1113 */
1114 function unsegmentForDiff( $text ) {
1115 return $text;
1116 }
1117
1118 # convert text to different variants of a language.
1119 function convert( $text, $isTitle = false) {
1120 return $this->mConverter->convert($text, $isTitle);
1121 }
1122
1123 # Convert text from within Parser
1124 function parserConvert( $text, &$parser ) {
1125 return $this->mConverter->parserConvert( $text, $parser );
1126 }
1127
1128 /**
1129 * Perform output conversion on a string, and encode for safe HTML output.
1130 * @param string $text
1131 * @param bool $isTitle -- wtf?
1132 * @return string
1133 * @todo this should get integrated somewhere sane
1134 */
1135 function convertHtml( $text, $isTitle = false ) {
1136 return htmlspecialchars( $this->convert( $text, $isTitle ) );
1137 }
1138
1139 function convertCategoryKey( $key ) {
1140 return $this->mConverter->convertCategoryKey( $key );
1141 }
1142
1143 /**
1144 * get the list of variants supported by this langauge
1145 * see sample implementation in LanguageZh.php
1146 *
1147 * @return array an array of language codes
1148 */
1149 function getVariants() {
1150 return $this->mConverter->getVariants();
1151 }
1152
1153
1154 function getPreferredVariant() {
1155 return $this->mConverter->getPreferredVariant();
1156 }
1157
1158 /**
1159 * if a language supports multiple variants, it is
1160 * possible that non-existing link in one variant
1161 * actually exists in another variant. this function
1162 * tries to find it. See e.g. LanguageZh.php
1163 *
1164 * @param string $link the name of the link
1165 * @param mixed $nt the title object of the link
1166 * @return null the input parameters may be modified upon return
1167 */
1168 function findVariantLink( &$link, &$nt ) {
1169 $this->mConverter->findVariantLink($link, $nt);
1170 }
1171
1172 /**
1173 * If a language supports multiple variants, converts text
1174 * into an array of all possible variants of the text:
1175 * 'variant' => text in that variant
1176 */
1177
1178 function convertLinkToAllVariants($text){
1179 return $this->mConverter->convertLinkToAllVariants($text);
1180 }
1181
1182
1183 /**
1184 * returns language specific options used by User::getPageRenderHash()
1185 * for example, the preferred language variant
1186 *
1187 * @return string
1188 * @public
1189 */
1190 function getExtraHashOptions() {
1191 return $this->mConverter->getExtraHashOptions();
1192 }
1193
1194 /**
1195 * for languages that support multiple variants, the title of an
1196 * article may be displayed differently in different variants. this
1197 * function returns the apporiate title defined in the body of the article.
1198 *
1199 * @return string
1200 */
1201 function getParsedTitle() {
1202 return $this->mConverter->getParsedTitle();
1203 }
1204
1205 /**
1206 * Enclose a string with the "no conversion" tag. This is used by
1207 * various functions in the Parser
1208 *
1209 * @param string $text text to be tagged for no conversion
1210 * @return string the tagged text
1211 */
1212 function markNoConversion( $text ) {
1213 return $this->mConverter->markNoConversion( $text );
1214 }
1215
1216 /**
1217 * A regular expression to match legal word-trailing characters
1218 * which should be merged onto a link of the form [[foo]]bar.
1219 *
1220 * @return string
1221 * @public
1222 */
1223 function linkTrail() {
1224 return $this->getMessage( 'linktrail' );
1225 }
1226
1227 function getLangObj() {
1228 return $this;
1229 }
1230
1231 /**
1232 * Get the RFC 3066 code for this language object
1233 */
1234 function getCode() {
1235 return str_replace( '_', '-', strtolower( substr( get_class( $this ), 8 ) ) );
1236 }
1237
1238
1239 }
1240
1241 # FIXME: Merge all UTF-8 support code into Language base class.
1242 # We no longer support Latin-1 charset.
1243 require_once( 'LanguageUtf8.php' );
1244
1245 # This should fail gracefully if there's not a localization available
1246 wfSuppressWarnings();
1247 // Preload base classes to work around APC/PHP5 bug
1248 include_once( 'Language' . str_replace( '-', '_', ucfirst( $wgLanguageCode ) ) . '.deps.php' );
1249 include_once( 'Language' . str_replace( '-', '_', ucfirst( $wgLanguageCode ) ) . '.php' );
1250 wfRestoreWarnings();
1251
1252 }
1253 ?>