3 * i18n class for Nucleus CMS
\r
4 * written by Takashi Sakamoto as of Feb 03, 2012
\r
6 * This includes wrapper functions of iconv and mbstring
\r
7 * for multibyte processing and includes parameters related to locale.
\r
9 * This program is free software; you can redistribute it and/or
\r
10 * modify it under the terms of the GNU General Public License
\r
11 * as published by the Free Software Foundation; either version 2
\r
12 * of the License, or (at your option) any later version.
\r
13 * (see nucleus/documentation/index.html#license for more info)
\r
15 * @license http://nucleuscms.org/license.txt GNU General Public License
\r
16 * @copyright Copyright (C) 2002-2011 The Nucleus Group
\r
17 * @version $Id: i18n.php 1678 2012-02-26 07:31:36Z sakamocchi $
\r
21 static private $mode = FALSE;
\r
23 static private $charset = '';
\r
24 static private $language = '';
\r
25 static private $script = '';
\r
26 static private $region = '';
\r
27 static private $locale_list = array();
\r
28 static private $timezone = 'UTC';
\r
32 * Initializing i18n class
\r
35 * @param string $charset character set
\r
38 static public function init($charset, $dir)
\r
40 /* i18n is already initialized */
\r
46 /* make locale list in this Nucleus CMS */
\r
47 if ( ($handle = opendir($dir)) === FALSE )
\r
51 while ($filename = readdir($handle))
\r
53 if (preg_match("#^(.+_.+_.+)\.{$charset}\.php$#", $filename, $matches) )
\r
55 if ( !in_array($matches[1], self::$locale_list) )
\r
57 self::$locale_list[] = $matches[1];
\r
63 /* set i18n backend and validate character set */
\r
64 if ( extension_loaded('iconv') )
\r
66 /* this is just for checking the charset. */
\r
67 if ( iconv_set_encoding('internal_encoding', $charset)
\r
68 && iconv_set_encoding('output_encoding', $charset)
\r
69 && iconv_set_encoding('internal_encoding', $charset) )
\r
71 self::$charset = $charset;
\r
72 self::$mode = 'iconv';
\r
75 else if ( extension_loaded('mbstring') )
\r
77 /* this is just for checking the charset. */
\r
78 if ( mb_http_output($charset)
\r
79 && mb_internal_encoding($charset)
\r
80 && mb_regex_encoding($charset) )
\r
82 self::$charset = $charset;
\r
83 self::$mode = 'mbstring';
\r
91 * i18n::get_available_locale_list
\r
92 * return available locale list with current charset
\r
96 * @return array available locale list
\r
98 static public function get_available_locale_list()
\r
100 return self::$locale_list;
\r
104 * i18n::get_current_charset
\r
105 * return current charset
\r
109 * @return string $charset current character set
\r
111 static public function get_current_charset()
\r
113 return self::$charset;
\r
118 * Set current locale
\r
121 * naming rule is "$language_$script_$region.$charset.php", refer to RFC 5646.
\r
122 * @link http://www.ietf.org/rfc/rfc5646.txt
\r
123 * @see 2. The Language Tag
\r
126 * @param string $locale
\r
127 * @return bool TRUE/FALSE
\r
130 static public function set_current_locale($locale)
\r
132 if ( preg_match('#^(.+)_(.+)_(.+)$#', $locale, $match) )
\r
134 self::$language = $match[1];
\r
135 self::$script = $match[2];
\r
136 self::$region = $match[3];
\r
144 * Get current locale
\r
150 static public function get_current_locale()
\r
152 $elements = array(self::$language, self::$script, self::$region);
\r
153 return implode('_', $elements);
\r
157 * i18n::confirm_default_date_timezone
\r
158 * to avoid E_NOTICE or E_WARNING generated when every calling to a date/time function.
\r
161 * Some private servers are lack of its timezone setting
\r
162 * http://www.php.net/manual/en/function.date-default-timezone-set.php
\r
168 static public function confirm_default_date_timezone()
\r
170 if ( function_exists('date_default_timezone_get')
\r
171 && FALSE !== ($timezone = @date_default_timezone_get()))
\r
173 self::$timezone = $timezone;
\r
175 if (function_exists('date_default_timezone_set')) {
\r
176 @date_default_timezone_set(self::$timezone);
\r
182 * i18n::get_current_date_timezone()
\r
183 * get current timezone
\r
187 * @return $timezone
\r
189 static public function get_date_timezone()
\r
191 return self::$timezone;
\r
196 * character set converter
\r
199 * @param string $string target string binary
\r
200 * @param string $from original character set encoding
\r
201 * @param string $to target character set encoding
\r
202 * @return string converted string
\r
204 static public function convert($string, $from, $to='')
\r
208 $to = self::$charset;
\r
211 if ( self::$mode == 'iconv' )
\r
213 $string = iconv($from, $to.'//TRANSLIT', $string);
\r
215 else if ( self::$mode == 'mbstring' )
\r
217 $string = mb_convert_encoding($string, $to, $from);
\r
219 return (string) $string;
\r
227 * @param string $string target string
\r
228 * @return integer the number of letters
\r
230 static public function strlen($string)
\r
233 if ( self::$mode == 'iconv' )
\r
235 $length = iconv_strlen($string, self::$charset);
\r
237 else if ( self::$mode == 'mbstring' )
\r
239 $length = mb_strlen($string, self::$charset);
\r
243 $length = strlen($string);
\r
245 return (integer) $length;
\r
253 * @param string $haystack string to search
\r
254 * @param string $needle string for search
\r
255 * @param integer $offset the position from which the search should be performed.
\r
256 * @return integer/FALSE the numeric position of the first occurrence of needle in haystack
\r
258 static public function strpos($haystack, $needle, $offset=0)
\r
261 if ( self::$mode == 'iconv' )
\r
263 $position = iconv_strpos($haystack, $needle, $offset, self::$charset);
\r
265 else if ( self::$mode == 'mbstring' )
\r
267 $position = mb_strpos($haystack, $needle, $offset, self::$charset);
\r
271 $position = strpos($haystack, $needle, $offset);
\r
274 if ( $position !== FALSE)
\r
276 $position = (integer) $position;
\r
286 * @param string $haystack string to search
\r
287 * @param string $needle string for search
\r
288 * @return integer/FALSE the numeric position of the last occurrence of needle in haystack
\r
290 static public function strrpos ($haystack, $needle)
\r
293 if ( self::$mode == 'iconv' )
\r
295 $position = iconv_strrpos($haystack, $needle, self::$charset);
\r
297 else if ( self::$mode == 'mbstring' )
\r
299 $position = mb_strrpos($haystack, $needle, 0, self::$charset);
\r
303 $position = strrpos($haystack, $needle, 0);
\r
306 if ( $position !== FALSE)
\r
308 $position = (integer) $position;
\r
318 * @param string $string string to be cut
\r
319 * @param string $start the position of starting
\r
320 * @param integer $length the length to be cut
\r
321 * @return string the extracted part of string
\r
323 static public function substr($string, $start, $length=0)
\r
326 if ( self::$mode == 'iconv' )
\r
328 $return = iconv_substr($string, $start, $length, self::$charset);
\r
330 else if ( self::$mode == 'mbstring' )
\r
332 $return = mb_substr($string, $start, $length, self::$charset);
\r
336 $return = strrpos($string, $start, $length);
\r
338 return (string) $return;
\r
343 * strftime function based on multibyte processing
\r
346 * @param string $format format with singlebyte or multibyte
\r
347 * @param timestamp $timestamp UNIX timestamp
\r
348 * @return string formatted timestamp
\r
350 static public function strftime($format, $timestamp='')
\r
354 if ( $timestamp == '' )
\r
356 $timestamp = time();
\r
359 if ( $format == '%%' )
\r
363 else if ( preg_match('#%[^%]#', $format) === 0 )
\r
368 $format = trim(preg_replace('#(%[^%])#', ',$1,', $format), ',');
\r
369 $elements = preg_split('#,#', $format);
\r
371 foreach ( $elements as $element )
\r
373 if ( preg_match('#(%[^%])#', $element) )
\r
375 $formatted .= strftime($element, $timestamp);
\r
377 else if ( $element == '%%' )
\r
383 $formatted .= $element;
\r
387 return (string) $formatted;
\r
391 * i18n::formatted_datetime()
\r
392 * return formatted datetime string
\r
394 * Date and Time Formats
\r
395 * @link http://www.w3.org/TR/NOTE-datetime
\r
397 * Working with Time Zones
\r
398 * @link http://www.w3.org/TR/timezone/
\r
400 * @param String $format time expression format
\r
401 * @param String $timestamp UNIX timestamp
\r
402 * @param Integer $offset timestamp offset
\r
403 * @return String formatted datetime
\r
405 static public function formatted_datetime($format, $timestamp, $offset=0)
\r
414 * MySQL 5.0 Reference Manual
\r
415 * 10.3.1. The DATE, DATETIME, and TIMESTAMP Types
\r
416 * http://dev.mysql.com/doc/refman/5.0/en/datetime.html
\r
418 $timestamp += $offset;
\r
419 $format = '%Y-%m-%d %H:%M:%S';
\r
424 * RFC 822: STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES
\r
425 * 5. DATE AND TIME SPECIFICATION
\r
426 * http://www.ietf.org/rfc/rfc0822.txt
\r
428 $format = '%a, %d %m %y %H:%M:%S ';
\r
432 $offset = -$offset;
\r
439 $suffix .= sprintf("%02d%02d", floor($offset / 3600), round(($offset % 3600) / 60) );
\r
443 * RFC 822: STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES
\r
444 * 5. DATE AND TIME SPECIFICATION
\r
445 * http://www.ietf.org/rfc/rfc0822.txt
\r
447 $format = '%a, %d %m %y %H:%M:%S ';
\r
448 $timestamp -= $offset;
\r
454 * RFC3339: Date and Time on the Internet: Timestamps
\r
455 * 5. Date and Time format
\r
456 * http://www.ietf.org/rfc/rfc3339.txt
\r
458 $format = '%Y-%m-%dT%H:%M:%S';
\r
462 $offset = -$offset;
\r
468 $suffix .= sprintf("%02d:%02d", floor($offset / 3600), round(($offset % 3600) / 60) );
\r
474 * RFC3339: Date and Time on the Internet: Timestamps
\r
475 * 5. Date and Time format
\r
476 * http://www.ietf.org/rfc/rfc3339.txt
\r
478 $timestamp -= $offset;
\r
479 $format = '%Y-%m-%dT%H:%M:%SZ';
\r
490 return i18n::strftime($format, $timestamp) . $suffix;
\r
494 * i18n::convert_locale_to_old_language_file_name()
\r
495 * NOTE: this should be obsoleted near future.
\r
498 * @param string $target_locale locale name as language_script_region
\r
499 * @return string old translation file name
\r
501 static public function convert_locale_to_old_language_file_name($target_locale)
\r
503 $target_language = '';
\r
504 foreach ( self::$lang_refs as $language => $locale )
\r
506 if ( preg_match('#-#', $language) )
\r
508 if ( $target_locale . '.' . self::$charset == $locale )
\r
510 $target_language = $language;
\r
514 else if ( $target_locale == $locale )
\r
516 $target_language = $language;
\r
519 return $target_language;
\r
523 * i18n::convert_old_language_file_name_to_locale()
\r
524 * NOTE: this should be obsoleted near future.
\r
527 * @param string $target_language old translation file name
\r
528 * @return string locale name as language_script_region
\r
530 static public function convert_old_language_file_name_to_locale($target_language)
\r
532 $target_locale = '';
\r
533 foreach ( self::$lang_refs as $language => $locale )
\r
535 if ( $target_language == $language )
\r
537 if ( preg_match('#^(.+)\.(.+)$#', $locale, $match) )
\r
539 $target_locale = $match[1];
\r
543 $target_locale = $locale;
\r
548 return $target_locale;
\r
553 * reference table to convert old and new way to name translation files.
\r
554 * NOTE: this should be obsoleted as soon as possible.
\r
558 static private $lang_refs = array(
\r
559 "english" => "en_Latn_US",
\r
560 "english-utf8" => "en_Latn_US.UTF-8",
\r
561 "bulgarian" => "bg_Cyrl_BG",
\r
562 "finnish" => "fi_Latn_FU",
\r
563 "catalan" => "ca_Latn_ES",
\r
564 "french" => "fr_Latn_FR",
\r
565 "russian" => "ru_Cyrl_RU",
\r
566 "chinese" => "zh_Hans_CN",
\r
567 "simchinese" => "zh_Hans_CN",
\r
568 "chineseb5" => "zh_Hant_TW",
\r
569 "traditional_chinese" => "zh_Hant_TW",
\r
570 "galego" => "gl_Latn_ES",
\r
571 "german" => "de_Latn_DE",
\r
572 "korean-utf" => "ko_Kore_KR.UTF-8",
\r
573 "korean-euc-kr" => "ko_Kore_KR.EUC-KR",
\r
574 "slovak" => "sk_Latn_SK",
\r
575 "czech" => "cs_Latn_CZ",
\r
576 "hungarian" => "hu_Latn_HU",
\r
577 "latvian" => "lv_Latn_LV",
\r
578 "nederlands" => "nl_Latn_NL",
\r
579 "italiano" => "it_Latn_IT",
\r
580 "persian" => "fa_Arab_IR",
\r
581 "spanish" => "es_Latn_ES",
\r
582 "spanish-utf8" => "es_Latn_ES.UTF-8",
\r
583 "japanese-euc" => "ja_Jpan_JP.EUC-JP",
\r
584 "japanese-utf8" => "ja_Jpan_JP.UTF-8",
\r
585 "portuguese_brazil" => "pt_Latn_BR"
\r