Enable UTF-8 lower/upper case operations in SearchEngine,
[mediawiki.git] / languages / Language.php
blobf001ee6f5be36146c44ade9fdda8b1084f1a894e
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 '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' ),
301 if (!$wgCachedMessageArrays) {
302 require_once('Messages.php');
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); }
322 #--------------------------------------------------------------------------
323 # Internationalisation code
324 #--------------------------------------------------------------------------
326 class Language {
327 var $mConverter;
328 function __construct() {
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 # Global offset in minutes.
530 if( isset($wgLocalTZoffset) ) {
531 $hrDiff = $wgLocalTZoffset % 60;
532 $minDiff = $wgLocalTZoffset - ($hrDiff * 60);
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 );
542 # No difference ? Return time unchanged
543 if ( 0 == $hrDiff && 0 == $minDiff ) { return $ts; }
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 );
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.
561 *<code>
562 * function timeanddate([...], $format = true) {
563 * $datePreference = $this->dateFormat($format);
564 * [...]
565 *</code>
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
572 function dateFormat( $usePrefs = true ) {
573 global $wgUser;
575 if( is_bool( $usePrefs ) ) {
576 if( $usePrefs ) {
577 $datePreference = $wgUser->getOption( 'date' );
578 } else {
579 $options = $this->getDefaultUserOptions();
580 $datePreference = (string)$options['date'];
582 } else {
583 $datePreference = (string)$usePrefs;
586 // return int
587 if( $datePreference == '' ) {
588 return MW_DATE_DEFAULT;
591 return $datePreference;
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
605 function date( $ts, $adj = false, $format = true, $timecorrection = false ) {
606 global $wgUser, $wgAmericanDates;
608 if ( $adj ) { $ts = $this->userAdjust( $ts, $timecorrection ); }
610 $datePreference = $this->dateFormat( $format );
611 if( $datePreference == MW_DATE_DEFAULT ) {
612 $datePreference = $wgAmericanDates ? MW_DATE_MDY : MW_DATE_DMY;
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 );
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";
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
638 function time( $ts, $adj = false, $format = true, $timecorrection = false ) {
639 global $wgUser;
641 if ( $adj ) { $ts = $this->userAdjust( $ts, $timecorrection ); }
642 $datePreference = $this->dateFormat( $format );
644 $sep = $this->timeSeparator( $format );
646 $hh = substr( $ts, 8, 2 );
647 $mm = substr( $ts, 10, 2 );
648 $ss = substr( $ts, 12, 2 );
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;
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
666 function timeSeparator( $format ) {
667 return ':';
671 * String to insert between the time and the date in a combined
672 * string. Should include any relevant whitespace.
673 * @return string
675 function timeDateSeparator( $format ) {
676 return ', ';
680 * Return true if the time should display before the date.
681 * @return bool
682 * @private
684 function timeBeforeDate() {
685 return true;
688 function formatMonth( $month, $format ) {
689 return $this->getMonthName( $month );
692 function formatDay( $day, $format ) {
693 return $this->formatNum( 0 + $day, true );
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)
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
709 function timeanddate( $ts, $adj = false, $format = true, $timecorrection = false) {
710 global $wgUser;
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;
726 function getMessage( $key ) {
727 global $wgAllMessagesEn;
728 return @$wgAllMessagesEn[$key];
731 function getAllMessages() {
732 global $wgAllMessagesEn;
733 return $wgAllMessagesEn;
736 function iconv( $in, $out, $string ) {
737 # For most languages, this is a wrapper for iconv
738 return iconv( $in, $out, $string );
741 function ucfirst( $string ) {
742 # For most languages, this is a wrapper for ucfirst()
743 return ucfirst( $string );
746 function uc( $str ) {
747 return strtoupper( $str );
750 function lcfirst( $s ) {
751 return strtolower( $s{0} ). substr( $s, 1 );
754 function lc( $str ) {
755 return strtolower( $str );
758 function ucwords($str) {
759 return ucwords( strtolower( $str ) );
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 );
773 function checkTitleEncoding( $s ) {
774 global $wgInputEncoding;
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 );
782 if( ($wgInputEncoding != 'utf-8') and $ishigh and $isutf )
783 return @iconv( 'UTF-8', $wgInputEncoding, $s );
785 if( ($wgInputEncoding == 'utf-8') and $ishigh and !$isutf )
786 return utf8_encode( $s );
788 # Other languages can safely leave this function, or replace
789 # it with one to detect and convert another legacy encoding.
790 return $s;
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.
798 * @param string $in
799 * @return string
801 function stripForSearch( $in ) {
802 return strtolower( $in );
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;
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.
816 * @param string $s
817 * @return string
819 function firstChar( $s ) {
820 return $s[0];
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;
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;
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 );
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;
863 if( $enc == $wgInputEncoding ) {
864 return $s;
865 } else {
866 return $this->iconv( $enc, $wgInputEncoding, $s );
871 * For right-to-left language support
873 * @return bool
875 function isRTL() { return false; }
878 * A hidden direction mark (LRM or RLM), depending on the language direction
880 * @return string
882 function getDirMark() { return $this->isRTL() ? "\xE2\x80\x8F" : "\xE2\x80\x8E"; }
885 * To allow "foo[[bar]]" to extend the link over the whole word "foobar"
887 * @return bool
889 function linkPrefixExtension() { return false; }
891 function &getMagicWords() {
892 global $wgMagicWordsEn;
893 return $wgMagicWordsEn;
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() ) );
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];
915 $mw->mCaseSensitive = $rawEntry[0];
916 $mw->mSynonyms = array_slice( $rawEntry, 1 );
920 * Italic is unsuitable for some languages
922 * @public
924 * @param string $text The text to be emphasized.
925 * @return string
927 function emphasize( $text ) {
928 return "<em>$text</em>";
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".
939 * An example of this function being called:
940 * <code>
941 * wfMsg( 'message', $wgLang->formatNum( $num ) )
942 * </code>
944 * See LanguageGu.php for the Gujarati implementation and
945 * LanguageIs.php for the , => . and . => , implementation.
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
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); }
963 if ($wgTranslateNumerals) {
964 $s = $this->digitTransformTable();
965 if (!is_null($s)) { $number = strtr($number, $s); }
968 return $number;
972 * Adds commas to a given number
974 * @param mixed $_
975 * @return string
977 function commafy($_) {
978 return strrev((string)preg_replace('/(\d{3})(?=\d)(?!\d*\.)/','$1,',strrev($_)));
981 function digitTransformTable() {
982 return null;
985 function separatorTransformTable() {
986 return null;
991 * For the credit list in includes/Credits.php (action=credits)
993 * @param array $l
994 * @return string
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;
1008 return $s;
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!
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;
1022 if ( strlen( $string ) <= abs( $length ) ) {
1023 return $string;
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;
1035 * Grammatical transformations, needed for inflected languages
1036 * Invoked by putting {{grammar:case|word}} in a message
1038 * @param string $word
1039 * @param string $case
1040 * @return string
1042 function convertGrammar( $word, $case ) {
1043 global $wgGrammarForms;
1044 if ( isset($wgGrammarForms['en'][$case][$word]) ) {
1045 return $wgGrammarForms['en'][$case][$word];
1047 return $word;
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.
1056 * Invoked by putting {{plural:count|wordform1|wordform2}}
1057 * or {{plural:count|wordform1|wordform2|wordform3}}
1059 * Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}}
1061 * @param integer $count
1062 * @param string $wordform1
1063 * @param string $wordform2
1064 * @param string $wordform3 (optional)
1065 * @return string
1067 function convertPlural( $count, $w1, $w2, $w3) {
1068 return $count == '1' ? $w1 : $w2;
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
1077 function translateBlockExpiry( $str ) {
1079 $scBlockExpiryOptions = wfMsg( 'ipboptions' );
1081 if ( $scBlockExpiryOptions == '-') {
1082 return $str;
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>';
1094 return $str;
1098 * languages like Chinese need to be segmented in order for the diff
1099 * to be of any use
1101 * @param string $text
1102 * @return string
1104 function segmentForDiff( $text ) {
1105 return $text;
1109 * and unsegment to show the result
1111 * @param string $text
1112 * @return string
1114 function unsegmentForDiff( $text ) {
1115 return $text;
1118 # convert text to different variants of a language.
1119 function convert( $text, $isTitle = false) {
1120 return $this->mConverter->convert($text, $isTitle);
1123 # Convert text from within Parser
1124 function parserConvert( $text, &$parser ) {
1125 return $this->mConverter->parserConvert( $text, $parser );
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
1135 function convertHtml( $text, $isTitle = false ) {
1136 return htmlspecialchars( $this->convert( $text, $isTitle ) );
1139 function convertCategoryKey( $key ) {
1140 return $this->mConverter->convertCategoryKey( $key );
1144 * get the list of variants supported by this langauge
1145 * see sample implementation in LanguageZh.php
1147 * @return array an array of language codes
1149 function getVariants() {
1150 return $this->mConverter->getVariants();
1154 function getPreferredVariant() {
1155 return $this->mConverter->getPreferredVariant();
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
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
1168 function findVariantLink( &$link, &$nt ) {
1169 $this->mConverter->findVariantLink($link, $nt);
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
1178 function convertLinkToAllVariants($text){
1179 return $this->mConverter->convertLinkToAllVariants($text);
1184 * returns language specific options used by User::getPageRenderHash()
1185 * for example, the preferred language variant
1187 * @return string
1188 * @public
1190 function getExtraHashOptions() {
1191 return $this->mConverter->getExtraHashOptions();
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.
1199 * @return string
1201 function getParsedTitle() {
1202 return $this->mConverter->getParsedTitle();
1206 * Enclose a string with the "no conversion" tag. This is used by
1207 * various functions in the Parser
1209 * @param string $text text to be tagged for no conversion
1210 * @return string the tagged text
1212 function markNoConversion( $text ) {
1213 return $this->mConverter->markNoConversion( $text );
1217 * A regular expression to match legal word-trailing characters
1218 * which should be merged onto a link of the form [[foo]]bar.
1220 * @return string
1221 * @public
1223 function linkTrail() {
1224 return $this->getMessage( 'linktrail' );
1227 function getLangObj() {
1228 return $this;
1232 * Get the RFC 3066 code for this language object
1234 function getCode() {
1235 return str_replace( '_', '-', strtolower( substr( get_class( $this ), 8 ) ) );
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' );
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();