<?php
/**
* This file implements functions for handling locales and i18n.
*
* This file is part of the evoCore framework - {@link http://evocore.net/}
* See also {@link https://github.com/b2evolution/b2evolution}.
*
* @license GNU GPL v2 - {@link http://b2evolution.net/about/gnu-gpl-license}
*
* @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}
* Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
*
* @package evocore
*
* @todo Make it a class / global object!
* - Provide (static) functions to extract .po files / generate _global.php files (single quoted strings!)
*/
if( !defined('EVO_CONFIG_LOADED') ) die( 'Please, do not access this page directly.' );
// DEBUG: (Turn switch on or off to log debug info for specified category)
$GLOBALS['debug_locale'] = true;
// LOCALIZATION:
if( isset( $use_l10n ) && $use_l10n )
{ // We are going to use localization:
/**
* TRANSLATE!
*
* Translate a text to the desired locale or to the current locale.
*
* @param string String to translate, '' to get language file info (as in gettext spec)
* @param string locale to translate to, '' to use current locale
* @param array Array containing the following keys (all optional):
* - 'ext_transarray': A reference to an alternate array
* to use for the caching of the
* translated strings or NULL to use
* the internal array.
* - 'alt_basedir': Alternate base directory to search
* for translations, e. g. a plugin or
* skin directory.
* - 'for_helper': (boolean) Is the translation for the b2evoHelper object?
* @return string The translated string or the original string on error.
*
* @internal The last parameter/its 'alt_basedir' key is used by
* Plugin::T_() and Skin::T_().
*/
function T_( $string, $req_locale = '', $params = array() )
{
/**
* The translations keyed by locale.
*
* This array is only used if $params['ext_transarray'] === NULL.
*
* @var array
* @static
*/
static $_trans = array();
global $current_locale, $locales, $locales_path, $plugins_path;
global $evo_charset, $Debuglog;
$params = array_merge( array(
'ext_transarray' => NULL,
'alt_basedir' => '',
'for_helper' => false,
'add_transarray' => NULL,
), $params );
if( empty( $req_locale ) )
{ // By default we use the current locale
if( empty( $current_locale ) )
{ // don't translate if we have no locale
return $string;
}
$req_locale = $current_locale;
}
if( ! isset( $locales[$req_locale]['messages'] ) )
{
$Debuglog->add( 'No messages file path for locale. $locales["'
.$req_locale.'"] is '.var_export( @$locales[$req_locale], true ), 'locale' );
if( ! empty( $evo_charset ) ) // this extra check is needed, because $evo_charset may not yet be determined.. :/
{
$string = convert_charset( $string, $evo_charset, 'iso-8859-1' );
}
return $string;
}
$messages = $locales[$req_locale]['messages'];
if ( is_null( $params['ext_transarray'] ) )
{ // use our array
//$Debuglog->add( 'Using internal array', 'locale' );
$trans = & $_trans;
}
else
{ // use external array:
//$Debuglog->add( 'Using external array', 'locale' );
$trans = & $params['ext_transarray'];
}
if( ! isset( $trans[ $messages ] ) )
{ // Translations for current locale have not yet been loaded:
$Debuglog->add( 'We need to load a new translation file to translate: "'. $string.'"', 'locale' );
if ( $params['alt_basedir'] != '' )
{ // Load the translation file from the alternative base dir:
//$Debuglog->add( 'Using alternative basedir ['.$params['alt_basedir'].']', 'locale' );
$path = $params['alt_basedir'].'/locales/'.$messages.'/_global.php';
}
else
{ // Load our global translation file.
$path = $locales_path.$messages.'/_global.php';
}
if( file_exists($path) && is_readable($path) )
{
$Debuglog->add( 'T_: Loading file: '.$path, 'locale' );
include_once $path;
}
else
{
$Debuglog->add( 'T_: Messages file does not exist or is not readable: '.$path, 'locale' );
}
if( ! isset($trans[ $messages ] ) )
{ // Still not loaded... file doesn't exist, memorize that no translations are available
// echo 'file not found!';
$trans[ $messages ] = array();
}
else
{
if( ! isset($trans[$messages]['__meta__']) )
{ // Unknown/old messages format (< version 1):
$Debuglog->add( 'Found deprecated messages format (no __meta__ info).', 'locale' );
// Translate keys (e.g. 'foo\nbar') to real strings ("foo\nbar")
// Doing this here for all strings, is actually faster than doing it on key lookup (like it has been done before always)
foreach($trans[$messages] as $k => $v)
{
if( ($pos = strpos($k, '\\')) === false )
{ // fast-path-skip
continue;
}
// Replace string as done in the good old days:
$new_k = str_replace( array('\n', '\r', '\t'), array("\n", "\r", "\t"), $k );
if( $new_k != $k )
{
$trans[$messages][$new_k] = $v;
unset($trans[$messages][$k]);
}
}
}
}
}
if( ! empty( $params['add_transarray'] ) )
{
switch( $params['add_transarray'] )
{
case 'backoffice':
static $_backoffice_array = array();
$add_transarray_var = 'trans_backoffice';
${$add_transarray_var} = & $_backoffice_array;
$trans_file_name = '_back-office.php';
break;
case 'demo_contents':
static $_demo_contents_array = array();
$add_transarray_var = 'trans_demo_contents';
${$add_transarray_var} = & $_demo_contents_array;
$trans_file_name = '_demo-contents.php';
break;
default:
debug_die( 'Invalid additional translation array.' );
}
if( ! isset( ${$add_transarray_var}[ $messages ] ) )
{ // Additional translations for current locale have not yet been loaded:
$Debuglog->add( 'We need to load additional translation file to translate: "'. $string.'"', 'locale' );
if ( $params['alt_basedir'] != '' )
{ // Load the translation file from the alternative base dir:
//$Debuglog->add( 'Using alternative basedir ['.$params['alt_basedir'].']', 'locale' );
$path = $params['alt_basedir'].'/locales/'.$messages.'/'.$trans_file_name;
}
else
{ // Load our additional translation file.
$path = $locales_path.$messages.'/'.$trans_file_name;
}
if( file_exists($path) && is_readable($path) )
{
$Debuglog->add( 'T_: Loading additional file: '.$path, 'locale' );
include_once $path;
}
else
{
$Debuglog->add( 'T_: Messages file does not exist or is not readable: '.$path, 'locale' );
}
if( ! isset( ${$add_transarray_var}[ $messages ] ) )
{ // Still not loaded... file doesn't exist, memorize that no translations are available
// echo 'file not found!';
${$add_transarray_var}[ $messages ] = array();
}
else
{
if( ! isset( ${$add_transarray_var}[$messages]['__meta__'] ) )
{ // Unknown/old messages format (< version 1):
$Debuglog->add( 'Found deprecated messages format (no __meta__ info).', 'locale' );
// Translate keys (e.g. 'foo\nbar') to real strings ("foo\nbar")
// Doing this here for all strings, is actually faster than doing it on key lookup (like it has been done before always)
foreach( ${$add_transarray_var}[$messages] as $k => $v )
{
if( ($pos = strpos($k, '\\')) === false )
{ // fast-path-skip
continue;
}
// Replace string as done in the good old days:
$new_k = str_replace( array( '\n', '\r', '\t' ), array( "\n", "\r", "\t" ), $k );
if( $new_k != $k )
{
${$add_transarray_var}[$messages][$new_k] = $v;
unset( ${$add_transarray_var}[$messages][$k] );
}
}
}
}
}
}
// sam2kb> b2evolution creates _global.php files with "\n" line breaks, and we must normalize newlines
// in supplied string before trying to translate it. Otherwise strings won't match.
// fp> TODO: this is not really satisfying in the long term. We need our own
// parser that will extract T_() TS_() NT_() etc string and create a normalized potfile.
// Actually it sgould create several potfiles. One for general use, one for admin, one for install, etc.
// That way translators can concentrate on the most essential stuff first.
$search_string = str_replace( array("\r\n", "\r"), "\n", $string );
if( ! empty( $params['add_transarray'] ) && isset( ${$add_transarray_var}[ $messages ][ $search_string ] ) )
{ // If the string has been translated:
//$Debuglog->add( 'String ['.$string.'] found', 'locale' );
$r = ${$add_transarray_var}[ $messages ][ $search_string ];
if( isset( ${$add_transarray_var}[$messages]['__meta__']['charset']) )
{ // new format: charset in meta data:
$messages_charset = ${$add_transarray_var}[$messages]['__meta__']['charset'];
}
else
{ // old format.. extract charset from content type or fall back to setting from global locale definition:
$meta = ${$add_transarray_var}[$messages][''];
if( preg_match( '~^Content-Type: text/plain; charset=(.*);?$~m', $meta, $match ) )
{
$messages_charset = $match[1];
}
else
{
$messages_charset = $locales[$req_locale]['charset'];
}
// Set it accordingly to new format.
${$add_transarray_var}[$messages]['__meta__']['charset'] = $messages_charset;
}
}
elseif( isset( $trans[ $messages ][ $search_string ] ) )
{ // If the string has been translated:
//$Debuglog->add( 'String ['.$string.'] found', 'locale' );
$r = $trans[ $messages ][ $search_string ];
if( isset($trans[$messages]['__meta__']['charset']) )
{ // new format: charset in meta data:
$messages_charset = $trans[$messages]['__meta__']['charset'];
}
else
{ // old format.. extract charset from content type or fall back to setting from global locale definition:
$meta = $trans[$messages][''];
if( preg_match( '~^Content-Type: text/plain; charset=(.*);?$~m', $meta, $match ) )
{
$messages_charset = $match[1];
}
else
{
$messages_charset = $locales[$req_locale]['charset'];
}
// Set it accordingly to new format.
$trans[$messages]['__meta__']['charset'] = $messages_charset;
}
}
else
{
//$Debuglog->add( 'String ['.$string.'] not found', 'locale' );
// Return the English string:
$r = $string;
// $messages_charset = 'iso-8859-1'; // our .php file encoding
// fp> I am changing the above for the User custom field group labels (in theroy the php files are plain ASCII anyways!!)
$messages_charset = $evo_charset;
}
if( ! empty($evo_charset) ) // this extra check is needed, because $evo_charset may not yet be determined.. :/
{
$r = convert_charset( $r, $evo_charset, $messages_charset );
}
else
{
$Debuglog->add(sprintf('Warning: evo_charset not set to translate "%s"', htmlspecialchars($string)), 'locale');
}
if( $params['for_helper'] )
{ // translation is for the b2evoHelper object
add_js_translation( $string, $r );
}
//$Debuglog->add( 'Result: ['.$r.']', 'locale' );
return $r;
}
/**
* Translate strings in Back-office UI.
*
* @param string String to translate
* @return string The translated string
*/
function TB_( $string, $req_locale = '', $params = array() )
{
$params = array_merge( array(
'add_transarray' => 'backoffice',
), $params );
return T_( $string, $req_locale, $params );
}
/**
* Translate strings in demo/sample contents.
*
* @param string String to translate
* @return string The translated string
*/
function TD_( $string, $req_locale = '', $params = array() )
{
// TODO: Later we will make a specific .POT file containing ONLY demo contents.
$params = array_merge( array(
'add_transarray' => 'demo_contents',
), $params );
return T_( $string, $req_locale, $params );
}
}
else
{ // We are not localizing at all:
/**
* @ignore
*/
function T_( $string, $req_locale = '', $params = array() )
{
return $string;
}
/**
* @ignore
*/
function TB_( $string, $req_locale = '', $params = array() )
{
return $string;
}
/**
* @ignore
*/
function TD_( $string, $req_locale = '', $params = array() )
{
return $string;
}
}
/**
* Translate and escape single quotes.
*
* This is to be used mainly for Javascript strings.
*
* @uses T_()
* @param string String to translate
* @param string Locale to use
* @param array See {@link T_()}
* @return string The translated and escaped string.
*/
function TS_( $string, $req_locale = '', $params = array() )
{
return str_replace( "'", "\\'", T_( $string, $req_locale, $params ) );
}
/**
* Temporarily switch to another locale
*
* Calls can be nested, see {@link locale_restore_previous()}.
*
* @param string locale to activate
* @return boolean true on success, false on failure
*/
function locale_temp_switch( $locale )
{
global $saved_locales, $current_locale, $Timer;
// $Timer->resume( 'locale_temp_switch' );
if( !isset( $saved_locales ) || ! is_array( $saved_locales ) )
{
$saved_locales = array();
}
$prev_locale = $current_locale;
if( locale_activate( $locale ) )
{
array_push( $saved_locales, $prev_locale );
return true;
}
// $Timer->stop( 'locale_temp_switch' );
return false;
}
/**
* Restore the locale in use before the switch
*
* @see locale_temp_switch()
* @return boolean true on success, false on failure (no locale stored before)
*/
function locale_restore_previous()
{
global $saved_locales;
if( !empty( $saved_locales ) && is_array( $saved_locales ) )
{
locale_activate( array_pop( $saved_locales ) );
return true;
}
return false;
}
/**
* Activate a locale.
*
* @todo dh> this should make sure, that e.g. "charset" is set for the locale in {@link $locales}. See http://forums.b2evolution.net/viewtopic.php?p=43980#43980
*
* @param string locale to activate
* @param boolean True on success/change, false on failure (if already set or not existant)
*/
function locale_activate( $locale )
{
global $locales, $current_locale, $current_charset;
if( $locale == $current_locale
|| empty( $locale )
|| ! isset( $locales[$locale] ) )
{
return false;
}
// Memorize new locale:
$current_locale = $locale;
// Memorize new charset:
$current_charset = $locales[ $locale ][ 'charset' ];
return true;
}
/**
* locale_by_lang(-)
*
* Find first locale matching lang
*/
function locale_by_lang( $lang, $fallback_to_default = true )
{
global $locales, $default_locale;
foreach( $locales as $locale => $locale_params )
{
if( substr( $locale, 0 ,2 ) == $lang )
{ // found first matching locale
return $locale;
}
}
// Not found...
if( $fallback_to_default )
return $default_locale;
else
return $lang;
}
/**
* Displays/Returns the current locale. (for backward compatibility)
*
* This is for HTML lang attributes
*
* @param boolean true (default) if we want it to be outputted
* @return string current locale, if $disp = false
*/
function locale_lang( $disp = true )
{
global $current_locale;
if( $disp )
echo $current_locale;
else
return $current_locale;
}
/**
* Returns the charset of the current locale
*/
function locale_charset( $disp = true )
{
global $current_charset;
if( $disp )
echo $current_charset;
else
return $current_charset;
}
/**
* Resolves a #date_format_code to the correct date or time format
*
* @param string Locale, must be set in {@link $locales}
* @return string Date format of the locale, e.g. 'd.m.Y'
*/
function locale_resolve_datetime_fmt( $format, $locale = NULL )
{
// Get datetime format:
switch( $format )
{
case '#short_date':
case '':
$format = locale_datefmt( $locale );
break;
case '#long_date':
$format = locale_longdatefmt( $locale );
break;
case '#extended_date':
$format = locale_extdatefmt( $locale );
break;
case '#short_time':
$format = locale_shorttimefmt( $locale );
break;
case '#long_time':
$format = locale_timefmt( $locale );
break;
case '#short_date_time':
$format = locale_datefmt( $locale ).' '.locale_shorttimefmt( $locale );
break;
}
return $format;
}
/**
* Returns the current locale's default date format
* @param string Locale, must be set in {@link $locales}
* @return string Date format of the locale, e.g. 'd.m.Y'
*/
function locale_datefmt( $locale = NULL )
{
return locale_get( 'datefmt', $locale );
}
/**
* Returns the current locale's default long date format
* @param string Locale, must be set in {@link $locales}
* @return string Date format of the locale, e.g. 'd.m.Y'
*/
function locale_longdatefmt( $locale = NULL )
{
global $locales;
if( empty($locale) )
{
global $current_locale;
$locale = $current_locale;
}
return $locales[$locale]['longdatefmt'];
}
/**
* Returns the current locale's default extended date format
* @param string Locale, must be set in {@link $locales}
* @return string Date format of the locale, e.g. 'd.m.Y'
*/
function locale_extdatefmt( $locale = NULL )
{
global $locales;
if( empty($locale) )
{
global $current_locale;
$locale = $current_locale;
}
return $locales[$locale]['extdatefmt'];
}
/**
* Returns the current locale's default input date format
* @param string Locale, must be set in {@link $locales}
* @return string Date format of the locale, e.g. 'd.m.Y'
*/
function locale_input_datefmt( $locale = NULL )
{
global $locales;
if( empty($locale) )
{
global $current_locale;
$locale = $current_locale;
}
return $locales[$locale]['input_datefmt'];
}
/**
* Returns the current locale's default time format
*/
function locale_timefmt()
{
return locale_get( 'timefmt' );
}
/**
* Returns the current locale's default short time format
*/
function locale_shorttimefmt()
{
return locale_get( 'shorttimefmt' );
}
function locale_datetimefmt( $separator = ' ' )
{
return locale_get( 'datefmt' ).$separator.locale_get( 'timefmt' );
}
/**
* Returns the current locale's start of week
*
* @return integer 0 for Sunday, 1 for Monday
*/
function locale_startofweek()
{
return ( int ) locale_get( 'startofweek' );
}
/**
* Get the country locale
*
* @param string locale to use, '' for current
*
* @return string country locale
*/
function locale_country( $locale = '' )
{
global $current_locale;
if( empty($locale) ) $locale = $current_locale;
return substr( $locale, 3, 2 );
}
/**
* Get the locale country dialing code
*/
function locale_dialing_code( $locale = '' )
{
global $current_locale, $CountryCache;
if( empty($locale) )
{
$locale = locale_country();
}
$edited_Country = $CountryCache->get_by_ID( $locale);
return $edited_Country->dialing_code;
}
/**
* Template function: Display locale flag
*
* @param string locale to use, '' for current
* @param string DEPRECATED PARAM - NOT USED IN THE FUNCTION ANYMORE !!
* @param string name of class for IMG tag !! OLD PARAM - NOT USED IN THE FUNCTION ANYMORE !!
* @param string deprecated HTML align attribute !! OLD PARAM - NOT USED IN THE FUNCTION ANYMORE !!
* @param boolean to echo or not
* @param mixed use absolute url (===true) or path to flags directory (used in installer) !! OLD PARAM - NOT USED IN THE FUNCTION ANYMORE !!
*/
function locale_flag( $locale = '', $collection = 'deprecated_param', $class = 'flag', $align = '', $disp = true, $absoluteurl = true )
{
global $locales, $current_locale, $country_flags_bg;
if( empty( $locale ) )
{
$locale = $current_locale;
}
// extract flag name:
$country_code = strtolower( substr( $locale, 3, 2 ) );
$flag_attribs = array(
'class' => 'flag',
'title' => isset($locales[$locale]['name']) ? $locales[$locale]['name'] : $locale,
);
if( isset( $country_flags_bg[ $country_code ] ) )
{ // Set background-position from config
$flag_attribs['style'] = 'background-position:'.$country_flags_bg[ $country_code ];
}
$r = '<span'.get_field_attribs_as_string( $flag_attribs ).'></span>';
if( $disp )
echo $r; // echo it
else
return $r; // return it
}
/**
* [callback function] Outputs an <option> set with default locale selected.
* Optionally returns an array with a locale key and name if there's only one enabled locale.
*
* @param string default value
* @param boolean echo output?
* @param boolean Return array (locale key + name) if there's only one enabled locale?
* @return string|array The options string or an array (locale key + name) if there's only one enabled locale and $array_if_onelocale == true.
*/
function locale_options( $default = '', $disp = true, $array_if_onelocale = false )
{
global $locales, $default_locale;
if( empty( $default ) ) $default = $default_locale;
$r = '';
$enabled_count = 0;
$enabled_lastkey = '';
foreach( $locales as $this_localekey => $this_locale )
{
if( $this_locale['enabled'] || $this_localekey == $default )
{
$r .= '<option value="'. $this_localekey. '"';
if( $this_localekey == $default )
$r .= ' selected="selected"';
$r .= '>'. T_($this_locale['name']). '</option>';
++$enabled_count;
$enabled_lastkey = $this_localekey;
}
}
if( $disp )
{ // the result must be displayed
echo $r;
}
if ( $array_if_onelocale && $enabled_count == 1 )
{ // We've only one enabled locale:
return array( $enabled_lastkey, $locales[$enabled_lastkey]['name'] );
}
else
{ // Return the string.
return $r;
}
}
/**
* [callback function] Returns an <option> set with default locale selected
*
* @param string default value
*/
function locale_options_return( $default = '' )
{
$r = locale_options( $default, false );
return $r;
}
/**
* Detect language from HTTP_ACCEPT_LANGUAGE
*
* HTTP_ACCEPT_LANGUAGE is sorted by prio and then the best match is used
* (either full locale ("en-US") or best fitting locale for a short one ("en").
*
* This gets tested in {@link test_locale_from_httpaccept()}.
*
* @author Rewritten by blueyed in Revision 1.42
*
* @return string Locale made out of HTTP_ACCEPT_LANGUAGE or $default_locale, if no match
*/
function locale_from_httpaccept()
{
global $locales, $default_locale;
if( isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) )
{
$accept = strtolower( $_SERVER['HTTP_ACCEPT_LANGUAGE'] );
// Create list of accepted locales.
if( ! preg_match_all('/([a-z]{1,8}(?:-[a-z]{1,8})?)\s*(?:;\s*q\s*=\s*(1|0(?:\.[0-9]+)?))?/i', $accept, $accept_list) )
{
return $default_locale;
}
// Create list of enabled locales.
$enabled_locales = array();
foreach($locales as $k => $v)
{
if( empty($v['enabled']) )
{
continue;
}
$enabled_locales[strtolower($k)] = $k;
}
if( empty($enabled_locales) )
{
return $default_locale;
}
// Build mapping of short code to long code(s)
$short_locales = array();
foreach($enabled_locales as $v)
{
if( $pos = strpos($v, '-') )
{
$short = substr($v, 0, $pos);
$short_locales[$short][] = $v;
}
}
// Create "locale" => "prio" list
$accept_list = array_combine($accept_list[1], $accept_list[2]);
$maxq = count($accept_list)+1;
foreach( $accept_list as $k => $v )
{
if( $v === '' )
{ // should be kept in order
$accept_list[$k] = $maxq--;
}
elseif( $v == 0 )
{ // not acceptable (RFC 2616)
unset($accept_list[$k]);
}
}
arsort($accept_list);
$accept_list = array_values(array_keys($accept_list));
// Go through the list of accepted locales and find best match.
for( $i = 0, $n = count($accept_list); $i<$n; $i++ )
{
$test = $accept_list[$i];
if( isset($enabled_locales[$test]) )
{ // the accepted locale is enabled and a full match
return $enabled_locales[$test];
}
if( isset($short_locales[$test]) )
{ // this is a short locale: find the best/first match in accepted locales
$first = NULL;
foreach($short_locales[$test] as $v)
{
$pos = array_search(strtolower($v), $accept_list);
if( $pos !== false && ( ! isset($first) || $pos < $first ) )
{
$first = $pos;
}
}
if( isset($first) )
{ // found exact match, via short locale.
return $enabled_locales[$accept_list[$first]];
}
if( isset($enabled_locales[$test.'-'.$test]) )
{ // test for e.g. "de-DE" when only "de" is accepted
return $enabled_locales[$test.'-'.$test];
}
// Fallback: use first enabled locale matching the short accepted
return $short_locales[$test][0];
}
}
}
return $default_locale;
}
/**
* user sort function to sort locales by priority
*
* 1 is highest priority.
*
*/
function locale_priosort( $a, $b )
{
return $a['priority'] - $b['priority'];
}
/**
* load locales from DB into $locales array. Also sets $default_locale.
*
* @return mixed new default locale on succes, false on failure
*/
function locale_overwritefromDB()
{
global $DB, $locales, $default_locale, $Settings, $Debuglog, $Messages;
// Load all locales from disk to get 'charset' insrtad of DB
locales_load_available_defs();
$usedprios = array(); // remember which priorities are used already.
$priocounter = 0;
$query = 'SELECT
loc_locale, loc_datefmt, loc_longdatefmt, loc_extdatefmt, loc_input_datefmt, loc_timefmt, loc_shorttimefmt, loc_input_timefmt, loc_startofweek,
loc_name, loc_messages, loc_priority, loc_transliteration_map, loc_enabled
FROM T_locales ORDER BY loc_priority';
$ctrl = isset( $_GET['ctrl'] ) ? $_GET['ctrl'] : '';
$priocounter_max = 0;
$wrong_locales = array();
$wrong_default_locale = '';
foreach( $DB->get_results( $query, ARRAY_A ) as $row )
{ // Loop through loaded locales:
if( $row['loc_priority'] == $priocounter )
{ // priority conflict (the same)
$priocounter++;
}
else
{
$priocounter = $row['loc_priority'];
}
$priocounter_max = $priocounter;
//remember that we used this
$usedprios[] = $priocounter;
$transliteration_map = '';
// Try to unserialize the value
if( ( $r = @unserialize( @base64_decode( $row[ 'loc_transliteration_map' ] ) ) ) !== false )
{
$transliteration_map = $r;
}
if( isset( $locales[ $row['loc_locale'] ], $locales[ $row['loc_locale'] ]['charset'] ) )
{ // Use charset from locale file if such file exists on disk
$loc_charset = $locales[ $row['loc_locale'] ]['charset'];
}
else
{ // Use charset from DB
$loc_charset = 'utf-8';
}
if( ( $ctrl == 'locales' || $ctrl == 'regional' ) && $row['loc_enabled'] && $loc_charset != 'utf-8' )
{ // Check wrong non utf-8 locales in order to deactivate them
$Messages->add( sprintf( T_('The locale %s has been deactivated because it\'s not UTF-8'), '<b>'.$row['loc_locale'].'</b>' ) );
if( $Settings->get( 'default_locale' ) == $row['loc_locale'] && $default_locale != $row['loc_locale'] )
{ // Change main locale to default
$wrong_default_locale = $row['loc_locale'];
$Messages->add( sprintf( T_('The main locale was no longer valid and has been set to %s.'), '<b>'.$default_locale.'</b>' ) );
}
$wrong_locales[] = $row['loc_locale'];
$row['loc_enabled'] = 0;
}
$locales[ $row['loc_locale'] ] = array(
'charset' => $loc_charset,
'datefmt' => $row['loc_datefmt'],
'longdatefmt' => $row['loc_longdatefmt'],
'extdatefmt' => $row['loc_extdatefmt'],
'input_datefmt' => $row['loc_input_datefmt'],
'timefmt' => $row['loc_timefmt'],
'shorttimefmt' => $row['loc_shorttimefmt'],
'input_timefmt' => $row['loc_input_timefmt'],
'startofweek' => $row['loc_startofweek'],
'name' => $row['loc_name'],
'messages' => $row['loc_messages'],
'transliteration_map' => $transliteration_map,
'priority' => $priocounter,
'enabled' => $row['loc_enabled'],
'fromdb' => 1
);
}
if( count( $wrong_locales ) )
{ // Deactivate locales that have wrong charset
$DB->query( 'UPDATE T_locales
SET loc_enabled = 0
WHERE loc_locale IN( '.$DB->quote( $wrong_locales ).' )' );
if( ! empty( $wrong_default_locale ) )
{ // If main locale is wring we sgould updated it to default and use this for all users and blogs that used this wrong locale
$Settings->set( 'default_locale', $default_locale );
$Settings->dbupdate();
$DB->query( 'UPDATE T_users
SET user_locale = '.$DB->quote( $default_locale ).'
WHERE user_locale = '.$DB->quote( $wrong_default_locale ) );
$DB->query( 'UPDATE T_blogs
SET blog_locale = '.$DB->quote( $default_locale ).'
WHERE blog_locale = '.$DB->quote( $wrong_default_locale ) );
}
}
foreach( $locales as $l_ley => $locale )
{ // Change priority of non-db locales to put them at the end of list
if( empty( $locale['fromdb'] ) && $locale['priority'] < $priocounter_max )
{
$locales[ $l_ley ]['priority'] = $priocounter_max + $locale['priority'];
}
}
// set default priorities, if nothing was set in DB.
// Missing "priority gaps" will get filled here.
if( $DB->num_rows != count($locales) )
{ // we have locales from conf file that need a priority
$priocounter = 1;
foreach( $locales as $lkey => $lval )
{ // Loop through memory locales:
if( !isset($lval['priority']) )
{ // Found one that has no assigned priority
while( in_array( $priocounter, $usedprios ) )
{
$priocounter++;
}
// Priocounter has max value
$locales[$lkey]['priority'] = $priocounter;
$usedprios[] = $priocounter;
}
}
}
// sort by priority
uasort( $locales, 'locale_priosort' );
// overwrite default_locale from DB settings - if enabled.
// Checks also if previous $default_locale is enabled. Defaults to en-EU, even if not enabled.
$locale_fromdb = $Settings->get('default_locale');
if( $locale_fromdb )
{
if( !isset( $locales[$locale_fromdb] ) )
{
$Debuglog->add( 'Default locale ['.$locale_fromdb.'] from general settings is not available.', 'locale' );
return false;
}
else
{
$default_locale = $locale_fromdb;
return $default_locale;
}
}
}
/**
* Write $locales array to DB table
*/
function locale_updateDB()
{
global $locales, $DB, $Settings, $Messages, $action, $admin_url;
global $saved_params;
$templocales = $locales;
$disabled_locales = array();
$saved_params = array();
$current_default_locale = $Settings->get( 'default_locale' );
$lnr = 0;
// Loop through list of all HTTP POSTed params:
foreach( $_POST as $pkey => $pval )
{
if( ! preg_match( '/loc_(\d+)_(.*)/', $pkey, $matches ) )
{
continue;
}
// This is a locale related parameter, get it now:
$pval = param( $pkey, 'string', '' );
$saved_params[ $pkey ] = $pval;
$lfield = $matches[2];
if( $matches[1] != $lnr )
{ // we have a new locale
$lnr = $matches[1];
$plocale = $pval;
if( $templocales[ $plocale ]['enabled'] || ( $plocale == $current_default_locale && ! isset( $_POST['loc_'.$lnr.'_enabled'] ) ) )
{ // Collect previously enabled locales AND if current default locale is not enabled yet:
$disabled_locales[ $plocale ] = $plocale;
}
// checkboxes default to 0
$templocales[ $plocale ]['enabled'] = 0;
}
elseif( $lnr != 0 ) // be sure to have catched a locale before
{
if( $lfield == 'datefmt' && empty( $pval ) )
{
param_error( $pkey, T_('Date format cannot be empty.').' ('.$plocale.')' );
}
elseif( $lfield == 'input_datefmt' && empty( $pval ) )
{
param_error( $pkey, T_('Input date format cannot be empty.').' ('.$plocale.')' );
}
elseif( $lfield == 'timefmt' && empty( $pval ) )
{
param_error( $pkey, T_('Time format cannot be empty.').' ('.$plocale.')' );
}
elseif( $lfield == 'input_timefmt' && empty( $pval ) )
{
param_error( $pkey, T_('Input time format cannot be empty.').' ('.$plocale.')' );
}
if( $lfield == 'startofweek' && ( $pval < 0 || $pval > 6 ) )
{ // startofweek must be between 0 and 6
continue;
}
if( $lfield == 'enabled' )
{ // This locale is enabled, remove from the list of the disabled locales
unset( $disabled_locales[ $plocale ] );
}
elseif( $plocale == $current_default_locale && isset( $disabled_locales[ $plocale ] ) && ! isset( $_POST['loc_'.$lnr.'_enabled'] ) )
{ // The default locale must be always enabled
unset( $disabled_locales[ $plocale ] );
// Force the default locale to be enabled
$templocales[ $plocale ]['enabled'] = 1;
// Inform user about this action
$Messages->add( sprintf( T_('The locale %s was re-enabled automatically because it\'s currently the default locale. The default locale must be a valid and enabled locale.'), '<b>'.$current_default_locale.'</b>' ), 'warning' );
}
$templocales[ $plocale ][ $lfield ] = $pval;
}
}
if( $Messages->has_errors() )
{
return false;
}
$locales = $templocales;
// Check the usage of the disabled locales
$disabled_locales = ( count( $disabled_locales ) > 0 ) ? $DB->quote( $disabled_locales ) : false;
if( $disabled_locales && ( $action != 'confirm_update' ) )
{ // Some locales were disabled, create warning message if required
global $warning_message;
$warning_message = '';
// Display what MAIN collection locales will be disabled:
$SQL = new SQL( 'Get collections with disabled main locales' );
$SQL->SELECT( 'blog_locale, GROUP_CONCAT( blog_ID SEPARATOR "," ) ' );
$SQL->FROM( 'T_blogs' );
$SQL->WHERE( 'blog_locale IN ( '.$disabled_locales.' )' );
$SQL->ORDER_BY( 'blog_locale' );
$SQL->GROUP_BY( 'blog_locale' );
$SQL->HAVING( 'COUNT( blog_ID ) > 0' );
$main_locale_colls = $DB->get_assoc( $SQL );
if( count( $main_locale_colls ) > 0 )
{
$BlogCache = & get_BlogCache();
$BlogCache->load_list( explode( ',', implode( ',', $main_locale_colls ) ) );
foreach( $main_locale_colls as $main_locale => $main_locale_coll_IDs )
{
$warning_message .= sprintf( T_('The locale %s is used as main locale by the following collections:'), '<code>'.$main_locale.'</code>' ).'<ul style="list-style:disc;margin-left:20px">';
$main_locale_coll_IDs = explode( ',', $main_locale_coll_IDs );
foreach( $main_locale_coll_IDs as $main_locale_coll_ID )
{
$locale_Blog = & $BlogCache->get_by_ID( $main_locale_coll_ID );
$coll_url = check_user_perm( 'blog_properties', 'edit', false, $main_locale_coll_ID )
? $admin_url.'?ctrl=coll_settings&tab=general&blog='.$locale_Blog->ID.'#fieldset_wrapper_language'
: $locale_Blog->get( 'url' );
$warning_message .= '<li><a href="'.$coll_url.'">'.$locale_Blog->get( 'name' ).'</a></li>';
}
$warning_message .= '</ul>'.sprintf( T_('These will be switched to the default locale %s.'), '<code>'.$main_locale.'</code>' ).'<br><br>';
}
}
// Display what EXTRA collection locales will be disabled:
$SQL = new SQL( 'Get collections with disabled extra locales' );
$SQL->SELECT( 'cl_locale, GROUP_CONCAT( cl_coll_ID SEPARATOR "," ) ' );
$SQL->FROM( 'T_coll_locales' );
$SQL->WHERE( 'cl_locale IN ( '.$disabled_locales.' )' );
$SQL->ORDER_BY( 'cl_locale' );
$SQL->GROUP_BY( 'cl_locale' );
$SQL->HAVING( 'COUNT( cl_coll_ID ) > 0' );
$extra_locale_colls = $DB->get_assoc( $SQL );
if( count( $extra_locale_colls ) > 0 )
{
$BlogCache = & get_BlogCache();
$BlogCache->load_list( explode( ',', implode( ',', $extra_locale_colls ) ) );
foreach( $extra_locale_colls as $extra_locale => $extra_locale_coll_IDs )
{
$warning_message .= sprintf( T_('The locale %s is also used as extra locale by the following collections:'), '<code>'.$extra_locale.'</code>' ).'<ul style="list-style:disc;margin-left:20px">';
$extra_locale_coll_IDs = explode( ',', $extra_locale_coll_IDs );
foreach( $extra_locale_coll_IDs as $extra_locale_coll_ID )
{
$locale_Blog = & $BlogCache->get_by_ID( $extra_locale_coll_ID );
$coll_url = check_user_perm( 'blog_properties', 'edit', false, $extra_locale_coll_ID )
? $admin_url.'?ctrl=coll_settings&tab=general&blog='.$locale_Blog->ID.'#fieldset_wrapper_language'
: $locale_Blog->get( 'url' );
$warning_message .= '<li><a href="'.$coll_url.'">'.$locale_Blog->get( 'name' ).'</a></li>';
}
$warning_message .= '</ul>'.sprintf( T_('These collections will no longer use the %s extra locale.'), '<code>'.$extra_locale.'</code>' ).'<br><br>';
}
}
// Display what USER locales will be disabled:
$SQL = new SQL( 'Get users with disabled locales' );
$SQL->SELECT( 'user_locale, GROUP_CONCAT( user_ID SEPARATOR "," ) ' );
$SQL->FROM( 'T_users' );
$SQL->WHERE( 'user_locale IN ( '.$disabled_locales.' )' );
$SQL->ORDER_BY( 'user_locale' );
$SQL->GROUP_BY( 'user_locale' );
$SQL->HAVING( 'COUNT( user_ID ) > 0' );
$locale_users = $DB->get_assoc( $SQL );
if( count( $locale_users ) > 0 )
{
$UserCache = & get_UserCache();
$UserCache->load_list( explode( ',', implode( ',', $locale_users ) ) );
foreach( $locale_users as $user_locale => $locale_user_IDs )
{
$warning_message .= sprintf( T_('The locale %s is also used as preferred locale by the following users:'), '<code>'.$user_locale.'</code>' ).'<ul style="list-style:disc;margin-left:20px">';
$locale_user_IDs = explode( ',', $locale_user_IDs );
foreach( $locale_user_IDs as $locale_user_ID )
{
$locale_User = & $UserCache->get_by_ID( $locale_user_ID );
$warning_message .= '<li>'.$locale_User->get_identity_link( array( 'user_tab' => 'userprefs' ) ).'</li>';
}
$warning_message .= '</ul>'.sprintf( T_('These users\' preferred locale will fall back to %s.'), '<code>'.$user_locale.'</code>' ).'<br><br>';
}
}
if( ! empty( $warning_message ) )
{
return false;
}
}
$query = "REPLACE INTO T_locales ( loc_locale, loc_datefmt, loc_longdatefmt, loc_extdatefmt, loc_input_datefmt,
loc_timefmt, loc_shorttimefmt, loc_input_timefmt, loc_startofweek, loc_name, loc_messages, loc_priority,
loc_transliteration_map, loc_enabled ) VALUES ";
foreach( $locales as $localekey => $lval )
{
if( empty($lval['messages']) )
{ // if not explicit messages file is given we'll translate the locale
$lval['messages'] = strtr($localekey, '-', '_');
}
$transliteration_map = '';
if( !empty($lval['transliteration_map']) )
{
if( is_string($lval['transliteration_map']) )
{ // The value is already serialized and encoded
$transliteration_map = $lval['transliteration_map'];
}
else
{ // Encode the value
$transliteration_map = base64_encode( serialize($lval['transliteration_map']) );
}
}
$query .= '(
'.$DB->quote($localekey).',
'.$DB->quote($lval['datefmt']).',
'.$DB->quote($lval['longdatefmt']).',
'.$DB->quote($lval['extdatefmt']).',
'.$DB->quote($lval['input_datefmt']).',
'.$DB->quote($lval['timefmt']).',
'.$DB->quote($lval['shorttimefmt']).',
'.$DB->quote($lval['input_timefmt']).',
'.$DB->quote($lval['startofweek']).',
'.$DB->quote($lval['name']).',
'.$DB->quote($lval['messages']).',
'.$DB->quote($lval['priority']).',
'.$DB->quote($transliteration_map).',
'.$DB->quote($lval['enabled']).'
), ';
}
$query = substr($query, 0, -2);
$DB->begin();
$result = true;
if( $action == 'confirm_update' )
{ // Update users and blogs locale to the default if the prevously used locale was disabled
$users_update = $DB->query( 'UPDATE T_users
SET user_locale = '.$DB->quote( $current_default_locale ).'
WHERE user_locale IN ( '.$disabled_locales.' )' );
$colls_main_locales_update = $DB->query( 'UPDATE T_blogs
SET blog_locale = '.$DB->quote( $current_default_locale ).'
WHERE blog_locale IN ( '.$disabled_locales.' )' );
$colls_extra_locales_update = $DB->query( 'DELETE FROM T_coll_locales
WHERE cl_locale IN ( '.$disabled_locales.' )' );
$result = ( $users_update !== false ) && ( $colls_main_locales_update !== false ) && ( $colls_extra_locales_update !== false );
}
if( $result && ( $DB->query($query) !== false ) )
{ // Commit after successful update
$DB->commit();
return true;
}
// Some error occured, rollback the transaction and add error message
$DB->rollback();
$Messages->add( T_('Unexpected error occured, regional settings could not be updated.') );
return false;
}
/**
* Convert a string from one charset to another.
*
* @todo Implement iconv and PHP mapping tables
*
* @see can_convert_charsets()
* @param string String to convert
* @param string Target charset (TO)
* @param string Source charset (FROM)
* @return string Encoded string (if it cannot be converted it's the original one)
*/
function convert_charset( $string, $dest_charset, $src_charset )
{
if( isset( $GLOBALS['Timer'] ) )
{
$GLOBALS['Timer']->resume( 'convert_charset', false );
}
if( $dest_charset == $src_charset || $dest_charset == '' /* may happen if $evo_charset is not defined yet */ )
{ // no conversation required
if( isset( $GLOBALS['Timer'] ) )
{
$GLOBALS['Timer']->pause( 'convert_charset', false );
}
return $string;
}
if( function_exists( 'mb_convert_variables' ) )
{ // Convert by mbstring extension if it is enabled:
mb_convert_variables( $dest_charset, $src_charset, $string );
}
elseif( function_exists( 'iconv' ) )
{ // Convert by iconv extension it it is enabled:
$string = iconv( $src_charset, $dest_charset, $string );
}
if( isset( $GLOBALS['Timer'] ) )
{
$GLOBALS['Timer']->pause( 'convert_charset', false );
}
return $string;
}
/**
* Can we convert from charset A to charset B?
* @param string Target charset (TO)
* @param string Source charset (FROM)
* @return boolean
*/
function can_convert_charsets( $dest_charset, $src_charset )
{
if( empty($dest_charset) || empty($src_charset) )
{
return false;
}
if( function_exists('mb_internal_encoding') )
{ // mb_string extension:
$orig = mb_internal_encoding();
$r = false;
if( @mb_internal_encoding($dest_charset) && @mb_internal_encoding($src_charset) )
{ // we can set both encodings, so we should be able to convert:
$r = true;
}
mb_internal_encoding($orig);
return $r;
}
return false;
}
/**
* Can we check for valid encodings of strings, using {@link check_encoding()}?
*
* @return boolean
*/
function can_check_encoding()
{
return function_exists('mb_check_encoding');
}
/**
* Check if the string is valid for the specified encoding.
*
* @param string String to check
* @param string Encoding to check
* @return
*/
function check_encoding($str, $encoding)
{
if( function_exists('mb_check_encoding') )
{
return mb_check_encoding($str, $encoding);
}
return NULL;
}
/**
* Init charset handling between Input/Output ($io_charset) and the internal
* handling ($evo_charset).
*
* Check and possibly adjust {@link $evo_charset}.
*
* @staticvar boolean Used to only start mb_output_handler once
* @param string I/O (input/output) charset to use
* @return boolean true, if encoding has been changed
*/
function init_charsets( $req_io_charset )
{
static $mb_output_handler_started;
global $io_charset, $evo_charset, $Debuglog, $DB;
global $force_io_charset_if_accepted;
if( $req_io_charset == $io_charset )
{ // no conversation/init needed
return false;
}
// check, if we want to force a specific charset (e.g. 'utf-8'):
if( ! empty($force_io_charset_if_accepted) )
{ // we want to force a specific charset:
if( ! isset($_SERVER['HTTP_ACCEPT_CHARSET']) // all allowed
|| preg_match( '~\b(\*|'.preg_quote( $force_io_charset_if_accepted, '~' ).')\b~', $_SERVER['HTTP_ACCEPT_CHARSET'] ) )
{
$req_io_charset = $force_io_charset_if_accepted; // pretend that the first one has been requested
}
}
if( $req_io_charset == $io_charset )
{ // no conversation/init needed
return false;
}
$io_charset = $req_io_charset;
if( empty($evo_charset) )
{ // empty evo_charset follows I/O charset:
// TODO: $evo_charset will not follow, if it has followed before.. (because not empty anymore)
$Debuglog->add( '$evo_charset follows $io_charset ('.$io_charset.').', array('locale') );
$evo_charset = $io_charset;
}
elseif( $evo_charset != $io_charset )
{ // we have to convert for I/O
// TODO: dh> $io_charset has to forcefully follow $evo_charset, if we cannot convert, e.g. utf-8/iso-8859-1
if( ! function_exists('mb_convert_encoding') )
{
$Debuglog->add( '$evo_charset differs from $io_charset, but mbstrings is not available - cannot convert I/O to internal charset!', array('errors','locale') );
$evo_charset = $io_charset; // we cannot convert I/O to internal charset
}
else
{ // check if the encodings are supported:
// NOTE: mb_internal_encoding() is the best way to find out if the encoding is supported
$old_mb_internal_encoding = mb_internal_encoding();
if( ! @mb_internal_encoding($io_charset) )
{
$Debuglog->add( 'Cannot I/O convert because I/O charset ['.$io_charset.'] is not supported by mbstring!', array('error','locale') );
$evo_charset = $io_charset;
mb_internal_encoding($old_mb_internal_encoding);
}
elseif( ! @mb_internal_encoding($evo_charset) )
{
$Debuglog->add( 'Cannot I/O convert because $evo_charset='.$evo_charset.' is not supported by mbstring!', array('error','locale') );
$evo_charset = $io_charset;
mb_internal_encoding($old_mb_internal_encoding);
}
else
{ // we can convert between I/O
mb_http_output( $io_charset );
if( ! $mb_output_handler_started )
{
ob_start( 'mb_output_handler' ); // NOTE: this will send a Content-Type header by itself for "text/..."
$mb_output_handler_started = true;
$Debuglog->add( 'Started mb_output_handler.', 'locale' );
}
}
}
}
// Make sure the DB send us text in the same charset as $evo_charset (override whatever may have been set before)
if( isset($DB) ) // not available in /install/index.php
{ // Set encoding for MySQL connection:
$DB->set_connection_charset( $evo_charset );
}
$Debuglog->add( 'evo_charset: '.$evo_charset, 'locale' );
$Debuglog->add( 'io_charset: '.$io_charset, 'locale' );
return true;
}
/**
* Load available locale definitions
*/
function locales_load_available_defs()
{
global $locales_path, $locales, $locales_loaded_form_disk, $Messages;
if( ! empty( $locales_loaded_form_disk ) )
{ // All locales have been already loaded
return;
}
// This is where language packs will store their locale defintions:
$locale_defs = array();
// Get all locale folder names:
$filename_params = array(
'inc_files' => false,
'recurse' => false,
'basename' => true,
);
$locale_folders = get_filenames( $locales_path, $filename_params );
// Go through all locale folders:
foreach( $locale_folders as $locale_folder )
{
//pre_dump( $locale_folder );
$ad_locale_folder = $locales_path.'/'.$locale_folder;
// Get files in folder:
$filename_params = array(
'inc_dirs' => false,
'recurse' => false,
'basename' => true,
);
$locale_def_files = get_filenames( $ad_locale_folder, $filename_params );
if( $locale_def_files === false )
{ // Impossible to read the locale folder:
$Messages->add( sprintf( /* No trans for debug messages */ 'The locale %s is not readable. Please check file permissions.', $locale_folder ), 'warning' );
continue;
}
// Go through files in locale folder:
foreach( $locale_def_files as $locale_def_file )
{ // Check if it's a definition file:
// pre_dump( $locale_def_file );
if( preg_match( '~[a-z0-9\-.]\.locale\.php$~i', $locale_def_file ) )
{ // We found a definition file:
// pre_dump( $locale_def_file );
include $ad_locale_folder.'/'.$locale_def_file;
}
}
}
// Copy any new locale definitions over to $locales:
foreach( $locale_defs as $locale_code => $locale_def )
{
if( !isset( $locales[$locale_code] ) )
{ // New locale, add to main array:
$locales[$locale_code] = $locale_def;
// ... but mark as not enabled!
$locales[$locale_code]['enabled'] = 0;
}
}
// Assign priorities:
// Find highest used priority:
$max_prio = 0;
foreach( $locales as $locale )
{
if( isset($locale['priority']) && $locale['priority'] > $max_prio )
{
$max_prio = $locale['priority'];
}
}
foreach( $locales as $lkey => $locale )
{
if( !isset($locale['priority']) )
{
$locales[$lkey]['priority'] = ++$max_prio;
}
}
// Set this var to TRUE to don't call this function twice
$locales_loaded_form_disk = true;
}
/**
* Get a number of the messages in the .PO & .POT file
*
* @param string File name (messages.po)
* @param boolean TRUE - to calc a percent of translated messages
* @return integer Number of the messages
*/
function locale_file_po_info( $po_file_name, $calc_percent_done = false )
{
$all = 0;
$fuzzy = 0;
$this_fuzzy = false;
$untranslated = 0;
$translated = 0;
$status = '-';
$matches = array();
if( file_exists( $po_file_name ) )
{
$lines = file( $po_file_name );
$lines[] = ''; // Adds a blank line at the end in order to ensure complete handling of the file
foreach( $lines as $line )
{
if( trim( $line ) == '' )
{ // Blank line, go back to base status:
if( $status == 't' )
{ // ** End of a translation ** :
if( $msgstr == '' )
{
$untranslated++;
// echo 'untranslated: ', $msgid, '<br />';
}
else
{
$translated++;
}
if( $msgid == '' && $this_fuzzy )
{ // It's OK if first line is fuzzy
$fuzzy--;
}
$msgid = '';
$msgstr = '';
$this_fuzzy = false;
}
$status = '-';
}
elseif( ( $status == '-' ) && preg_match( '#^msgid "(.*)"#', $line, $matches ) )
{ // Encountered an original text
$status = 'o';
$msgid = $matches[1];
// echo 'original: "', $msgid, '"<br />';
$all++;
}
elseif( ( $status == 'o' ) && preg_match( '#^msgstr "(.*)"#', $line, $matches ) )
{ // Encountered a translated text
$status = 't';
$msgstr = $matches[1];
// echo 'translated: "', $msgstr, '"<br />';
}
elseif( preg_match( '#^"(.*)"#', $line, $matches ) )
{ // Encountered a followup line
if( $status == 'o' )
$msgid .= $matches[1];
elseif( $status == 't' )
$msgstr .= $matches[1];
}
elseif( strpos( $line,'#, fuzzy' ) === 0 )
{
$this_fuzzy = true;
$fuzzy++;
}
}
}
$info = array(
'all' => $all,
'fuzzy' => $fuzzy,
'translated' => $translated,
'untranslated' => $untranslated
);
if( $calc_percent_done )
{
$po_path_info = pathinfo( $po_file_name );
$pot_file_name = $po_path_info['filename'].'.pot';
$info['percent'] = locale_file_po_percent_done( $info, $pot_file_name );
}
return $info;
}
/**
* Get a percent of translated messages in the .PO file
*
* @param array File info (see result of the function locale_file_po_info() )
* @return integer Percent
*/
function locale_file_po_percent_done( $po_file_info, $pot_file )
{
global $messages_pot_file_info;
if( !isset( $messages_pot_file_info[$pot_file] ) )
{ // Initialize a file info for the main language file if it doesn't yet set
global $locales_path;
$messages_pot_file_info[$pot_file] = locale_file_po_info( $locales_path.$pot_file );
}
$percent_done = ( $messages_pot_file_info[$pot_file]['all'] > 0 ) ? round( ( $po_file_info['translated'] - $po_file_info['fuzzy'] / 2 ) / $messages_pot_file_info[$pot_file]['all'] * 100 ) : 0;
return $percent_done;
}
/**
* Insert default locales into T_locales.
*/
function locale_insert_default()
{
global $DB, $current_locale, $locales, $install_test_features;
$activate_locales = array();
if( ! empty( $install_test_features ) )
{ // Activate also additional locales on install:
$activate_locales[] = 'en-US';
$activate_locales[] = 'de-DE';
$activate_locales[] = 'fr-FR';
$activate_locales[] = 'ru-RU';
}
if( ! empty( $current_locale ) )
{ // Make sure the user sees his new system localized.
$activate_locales[] = $current_locale;
}
$activate_locales = array_unique( $activate_locales );
if( ! empty( $activate_locales ) )
{ // Insert locales into DB
$SQL = new SQL( 'Get locales' );
$SQL->SELECT( 'loc_locale' );
$SQL->FROM( 'T_locales' );
$existing_locales = $DB->get_col( $SQL );
$insert_data = array();
foreach( $activate_locales as $a_locale )
{
if( !isset( $locales[ $a_locale ] ) || in_array( $a_locale, $existing_locales ) )
{ // Skip an incorrect locale or it already exists in DB
continue;
}
// Make sure default transliteration_map is set
$transliteration_map = '';
if( isset( $locales[ $a_locale ]['transliteration_map'] ) && is_array( $locales[ $a_locale ]['transliteration_map'] ) )
{
$transliteration_map = base64_encode( serialize( $locales[ $a_locale ]['transliteration_map'] ) );
}
$insert_data[] = '( '.$DB->quote( $a_locale ).', '
.$DB->quote( $locales[ $a_locale ]['datefmt'] ).', '
.$DB->quote( empty( $locales[ $a_locale ]['longdatefmt'] ) ? str_replace( 'y', 'Y', $locales[ $a_locale ]['datefmt'] ) : $locales[ $a_locale ]['longdatefmt'] ).', '
.$DB->quote( empty( $locales[ $a_locale ]['extdatefmt'] ) ? str_replace( array( '.', ',', '\\', '/' ), ' ', str_replace( array( 'y', 'm' ), array( 'Y', 'M' ), $locales[ $a_locale ]['datefmt'] ) ) : $locales[ $a_locale ]['extdatefmt'] ).', '
.$DB->quote( $locales[ $a_locale ]['input_datefmt'] ).', '
.$DB->quote( $locales[ $a_locale ]['timefmt'] ).', '
.$DB->quote( empty( $locales[ $a_locale ]['shorttimefmt'] ) ? str_replace( ':s', '', $locales[ $a_locale ]['timefmt'] ) : $locales[ $a_locale ]['shorttimefmt'] ).', '
.$DB->quote( $locales[ $a_locale ]['input_timefmt'] ).', '
.$DB->quote( $locales[ $a_locale ]['startofweek'] ).', '
.$DB->quote( $locales[ $a_locale ]['name'] ).', '
.$DB->quote( $locales[ $a_locale ]['messages'] ).', '
.$DB->quote( $locales[ $a_locale ]['priority'] ).', '
.$DB->quote( $transliteration_map ).', '
.'1 )';
}
if( count( $insert_data ) )
{ // Do insert only if at least one locale requires this
$DB->query( 'INSERT INTO T_locales '
.'( loc_locale, loc_datefmt, loc_longdatefmt, loc_extdatefmt, loc_input_datefmt, loc_timefmt, loc_shorttimefmt, loc_input_timefmt, '
.'loc_startofweek, loc_name, loc_messages, loc_priority, '
.'loc_transliteration_map, loc_enabled ) '
.'VALUES '.implode( ', ', $insert_data ) );
}
}
}
/**
* Restore default values of locales
*
* @param array Locale keys/codes
*/
function locale_restore_defaults( $restored_locales )
{
global $DB, $locales;
if( empty( $restored_locales ) && ! is_array( $restored_locales ) )
{ // No locales to restore, Exit here:
return;
}
foreach( $restored_locales as $restored_locale_key )
{
if( ! isset( $locales[ $restored_locale_key ] ) )
{ // Skip an incorrect locale:
continue;
}
$restored_locale = $locales[ $restored_locale_key ];
// Make sure default transliteration_map is set:
$transliteration_map = '';
if( isset( $restored_locale['transliteration_map'] ) && is_array( $restored_locale['transliteration_map'] ) )
{
$transliteration_map = base64_encode( serialize( $restored_locale['transliteration_map'] ) );
}
// Restore all locale fields to default values:
$DB->query( 'UPDATE T_locales SET
loc_datefmt = '.$DB->quote( $restored_locale['datefmt'] ).',
loc_longdatefmt = '.$DB->quote( empty( $restored_locale['longdatefmt'] ) ? str_replace( 'y', 'Y', $restored_locale['datefmt'] ) : $restored_locale['longdatefmt'] ).',
loc_extdatefmt = '.$DB->quote( empty( $restored_locale['extdatefmt'] ) ? str_replace( array( '.', '-', '\\', '/'), ' ', str_replace( array( 'y', 'm' ), array( 'Y', 'M' ), $restored_locale['datefmt'] ) ) : $restored_locale['extdatefmt'] ).',
loc_input_datefmt = '.$DB->quote( $restored_locale['input_datefmt'] ).',
loc_timefmt = '.$DB->quote( $restored_locale['timefmt'] ).',
loc_shorttimefmt = '.$DB->quote( empty( $restored_locale['shorttimefmt'] ) ? str_replace( ':s', '', $restored_locale['timefmt'] ) : $restored_locale['shorttimefmt'] ).',
loc_input_timefmt = '.$DB->quote( $restored_locale['input_timefmt'] ).',
loc_startofweek = '.$DB->quote( $restored_locale['startofweek'] ).',
loc_name = '.$DB->quote( $restored_locale['name'] ).',
loc_messages = '.$DB->quote( $restored_locale['messages'] ).',
loc_priority = '.$DB->quote( $restored_locale['priority'] ).',
loc_transliteration_map = '.$DB->quote( $transliteration_map ).'
WHERE loc_locale = '.$DB->quote( $restored_locale_key ) );
}
}
/**
* Check default locale and enable if it is not yet
* Used after each upgrade process
*/
function locale_check_default()
{
global $DB, $Settings, $default_locale, $locales;
// Get default locale from DB:
$current_default_locale = $Settings->get( 'default_locale' );
if( isset( $locales[ $current_default_locale ] ) && $locales[ $current_default_locale ]['enabled'] )
{ // Current default locale is correct and enabled
// Nothing to fix, Exit here:
return;
}
if( ! isset( $locales[ $current_default_locale ] ) )
{ // If current default locale is wrong and doesn't exist anymore then use default locale from config:
$current_default_locale = $default_locale;
// Fix wrong default locale to correct value:
$Settings->set( 'default_locale', $current_default_locale );
$Settings->dbupdate();
}
// Get a row of current default locale in order to check if it is enabled:
$SQL = new SQL( 'Check if current default locale is enabled' );
$SQL->SELECT( 'loc_enabled' );
$SQL->FROM( 'T_locales' );
$SQL->WHERE( 'loc_locale = '.$DB->quote( $current_default_locale ) );
$current_default_locale_enabled = $DB->get_var( $SQL );
if( $current_default_locale_enabled !== NULL )
{ // Current default locale exists in DB
if( ! $current_default_locale_enabled )
{ // Enable current default locale if it is not enabled yet:
$DB->query( 'UPDATE T_locales
SET loc_enabled = 1
WHERE loc_locale = '.$DB->quote( $current_default_locale ) );
}
}
else
{ // No record of default locale
// Make sure default transliteration_map is set
$transliteration_map = '';
if( isset( $locales[ $current_default_locale ]['transliteration_map'] ) && is_array( $locales[ $current_default_locale ]['transliteration_map'] ) )
{
$transliteration_map = base64_encode( serialize( $locales[ $current_default_locale ]['transliteration_map'] ) );
}
// Insert default locale into DB in order to make it enabled:
$DB->query( 'INSERT INTO T_locales '
.'( loc_locale, loc_datefmt, loc_longdatefmt, loc_extdatefmt, loc_input_datefmt, loc_timefmt, loc_shorttimefmt, loc_input_timefmt, '
.'loc_startofweek, loc_name, loc_messages, loc_priority, '
.'loc_transliteration_map, loc_enabled ) '
.'VALUES ( '
.$DB->quote( $current_default_locale ).', '
.$DB->quote( $locales[ $current_default_locale ]['datefmt'] ).', '
.$DB->quote( empty( $locales[ $current_default_locale ]['longdatefmt'] ) ? str_replace( 'y', 'Y', $locales[ $current_default_locale ]['datefmt'] ) : $locales[ $current_default_locale ]['longdatefmt'] ).', '
.$DB->quote( empty( $locales[ $current_default_locale ]['extdatefmt'] ) ? str_replace( array( '.'. '-', '\\', '/' ), ' ', str_replace( array( 'y', 'm' ), array( 'Y', 'Y' ), $locales[ $current_default_locale ]['datefmt'] ) ) : $locales[ $current_default_locale ]['extdatefmt'] ).', '
.$DB->quote( $locales[ $current_default_locale ]['input_datefmt'] ).', '
.$DB->quote( $locales[ $current_default_locale ]['timefmt'] ).', '
.$DB->quote( empty( $locales[ $current_default_locale ]['shorttimefmt'] ) ? str_replace( ':s', '', $locales[ $current_default_locale ]['timefmt'] ) : $locales[ $current_default_locale ]['shorttimefmt'] ).', '
.$DB->quote( $locales[ $current_default_locale ]['input_timefmt'] ).', '
.$DB->quote( $locales[ $current_default_locale ]['startofweek'] ).', '
.$DB->quote( $locales[ $current_default_locale ]['name'] ).', '
.$DB->quote( $locales[ $current_default_locale ]['messages'] ).', '
.$DB->quote( $locales[ $current_default_locale ]['priority'] ).', '
.$DB->quote( $transliteration_map ).', '
.'1 )' );
}
}
/**
* Returns the locale's default field value
*
* @param string Locale field
* @param string Locale name, '#' to get default value not specific to a locale
* @param mixed Value to return if locale field is empty and no default value is assigned
* @return mixed Locale field value
*/
function locale_get( $field, $locale = NULL, $default = NULL )
{
global $locales;
if( is_null( $locale ) )
{
global $current_locale;
$locale = $current_locale;
}
if( $locale == '#' || empty( $locales[$locale][$field] ) )
{
$default_values = array(
'datefmt' => 'Y-m-d',
'longdatefmt' => 'Y-m-d',
'extdatefmt' => 'M d, Y',
'input_datefmt' => 'Y-m-d',
'timefmt' => 'H:i:s',
'shorttimefmt' => 'H:i',
'input_timefmt' => 'H:i:s'
);
switch( $field )
{
case 'longdatefmt':
if( isset( $locales[$locale]['datefmt'] ) )
{
return str_replace( 'y', 'Y', $locales[$locale]['datefmt'] );
}
else
{
return isset( $default ) ? $default : $default_values['longdatefmt'];
}
break;
case 'extdatefmt':
if( isset( $locales[$locale]['datefmt'] ) )
{
return str_replace( array( '.', '-', '\\', '/' ), ' ', str_replace( array( 'm', 'y' ), array( 'M', 'Y' ), $locales[$locale]['datefmt'] ) );
}
else
{
return isset( $default ) ? $default : $default_values['extdatefmt'];
}
break;
case 'shorttimefmt':
if( isset( $locales[$locale]['timefmt'] ) )
{
return str_replace( ':s', '', $locales[$locale]['timefmt'] );
}
else
{
return isset( $default ) ? $default : $default_values['shorttimefmt'];
}
break;
default:
return isset( $default_values[$field] ) ? $default_values[$field] : ( isset( $default ) ? $default : NULL );
}
}
else
{
return $locales[$locale][$field];
}
}
/**
* Set default values of locales formats
*
* @param array Locale
* @param array Source locale
*/
function locale_set_default_formats( & $locale, $source_locale = NULL )
{
if( is_null( $source_locale ) )
{
$source_locale = $locale;
}
foreach( $source_locale as $l_key => $l_value )
{
if( $default_value = locale_get( $l_key, $source_locale ) )
{
$locale[$l_key] = $default_value;
}
}
}
/**
* Provide normalizer_normalize for older versions of PHP < 5.3.0 and PECL intl < 1.0.0
*
* Normalizes the input provided and returns the normalized string
*
* @param string The input string to normalize
* @param integer One of the normalization forms
* @return string The normalized string or FALSE if an error occurred
*/
if( ! function_exists( 'normalizer_normalize' ) )
{
function normalizer_normalize( $input, $form = NULL )
{
$transliteration = array(
'IJ'=>'I','Ö'=>'O','Œ'=>'O','Ü'=>'U','ä'=>'a','æ'=>'a',
'ij'=>'i','ö'=>'o','œ'=>'o','ü'=>'u','ß'=>'s','ſ'=>'s',
'À'=>'A','Á'=>'A','Â'=>'A','Ã'=>'A','Ä'=>'A','Å'=>'A',
'Æ'=>'A','Ā'=>'A','Ą'=>'A','Ă'=>'A','Ç'=>'C','Ć'=>'C',
'Č'=>'C','Ĉ'=>'C','Ċ'=>'C','Ď'=>'D','Đ'=>'D','È'=>'E',
'É'=>'E','Ê'=>'E','Ë'=>'E','Ē'=>'E','Ę'=>'E','Ě'=>'E',
'Ĕ'=>'E','Ė'=>'E','Ĝ'=>'G','Ğ'=>'G','Ġ'=>'G','Ģ'=>'G',
'Ĥ'=>'H','Ħ'=>'H','Ì'=>'I','Í'=>'I','Î'=>'I','Ï'=>'I',
'Ī'=>'I','Ĩ'=>'I','Ĭ'=>'I','Į'=>'I','İ'=>'I','Ĵ'=>'J',
'Ķ'=>'K','Ľ'=>'K','Ĺ'=>'K','Ļ'=>'K','Ŀ'=>'K','Ł'=>'L',
'Ñ'=>'N','Ń'=>'N','Ň'=>'N','Ņ'=>'N','Ŋ'=>'N','Ò'=>'O',
'Ó'=>'O','Ô'=>'O','Õ'=>'O','Ø'=>'O','Ō'=>'O','Ő'=>'O',
'Ŏ'=>'O','Ŕ'=>'R','Ř'=>'R','Ŗ'=>'R','Ś'=>'S','Ş'=>'S',
'Ŝ'=>'S','Ș'=>'S','Š'=>'S','Ť'=>'T','Ţ'=>'T','Ŧ'=>'T',
'Ț'=>'T','Ù'=>'U','Ú'=>'U','Û'=>'U','Ū'=>'U','Ů'=>'U',
'Ű'=>'U','Ŭ'=>'U','Ũ'=>'U','Ų'=>'U','Ŵ'=>'W','Ŷ'=>'Y',
'Ÿ'=>'Y','Ý'=>'Y','Ź'=>'Z','Ż'=>'Z','Ž'=>'Z','à'=>'a',
'á'=>'a','â'=>'a','ã'=>'a','ā'=>'a','ą'=>'a','ă'=>'a',
'å'=>'a','ç'=>'c','ć'=>'c','č'=>'c','ĉ'=>'c','ċ'=>'c',
'ď'=>'d','đ'=>'d','è'=>'e','é'=>'e','ê'=>'e','ë'=>'e',
'ē'=>'e','ę'=>'e','ě'=>'e','ĕ'=>'e','ė'=>'e','ƒ'=>'f',
'ĝ'=>'g','ğ'=>'g','ġ'=>'g','ģ'=>'g','ĥ'=>'h','ħ'=>'h',
'ì'=>'i','í'=>'i','î'=>'i','ï'=>'i','ī'=>'i','ĩ'=>'i',
'ĭ'=>'i','į'=>'i','ı'=>'i','ĵ'=>'j','ķ'=>'k','ĸ'=>'k',
'ł'=>'l','ľ'=>'l','ĺ'=>'l','ļ'=>'l','ŀ'=>'l','ñ'=>'n',
'ń'=>'n','ň'=>'n','ņ'=>'n','ʼn'=>'n','ŋ'=>'n','ò'=>'o',
'ó'=>'o','ô'=>'o','õ'=>'o','ø'=>'o','ō'=>'o','ő'=>'o',
'ŏ'=>'o','ŕ'=>'r','ř'=>'r','ŗ'=>'r','ś'=>'s','š'=>'s',
'ť'=>'t','ù'=>'u','ú'=>'u','û'=>'u','ū'=>'u','ů'=>'u',
'ű'=>'u','ŭ'=>'u','ũ'=>'u','ų'=>'u','ŵ'=>'w','ÿ'=>'y',
'ý'=>'y','ŷ'=>'y','ż'=>'z','ź'=>'z','ž'=>'z','Α'=>'A',
'Ά'=>'A','Ἀ'=>'A','Ἁ'=>'A','Ἂ'=>'A','Ἃ'=>'A','Ἄ'=>'A',
'Ἅ'=>'A','Ἆ'=>'A','Ἇ'=>'A','ᾈ'=>'A','ᾉ'=>'A','ᾊ'=>'A',
'ᾋ'=>'A','ᾌ'=>'A','ᾍ'=>'A','ᾎ'=>'A','ᾏ'=>'A','Ᾰ'=>'A',
'Ᾱ'=>'A','Ὰ'=>'A','ᾼ'=>'A','Β'=>'B','Γ'=>'G','Δ'=>'D',
'Ε'=>'E','Έ'=>'E','Ἐ'=>'E','Ἑ'=>'E','Ἒ'=>'E','Ἓ'=>'E',
'Ἔ'=>'E','Ἕ'=>'E','Ὲ'=>'E','Ζ'=>'Z','Η'=>'I','Ή'=>'I',
'Ἠ'=>'I','Ἡ'=>'I','Ἢ'=>'I','Ἣ'=>'I','Ἤ'=>'I','Ἥ'=>'I',
'Ἦ'=>'I','Ἧ'=>'I','ᾘ'=>'I','ᾙ'=>'I','ᾚ'=>'I','ᾛ'=>'I',
'ᾜ'=>'I','ᾝ'=>'I','ᾞ'=>'I','ᾟ'=>'I','Ὴ'=>'I','ῌ'=>'I',
'Θ'=>'T','Ι'=>'I','Ί'=>'I','Ϊ'=>'I','Ἰ'=>'I','Ἱ'=>'I',
'Ἲ'=>'I','Ἳ'=>'I','Ἴ'=>'I','Ἵ'=>'I','Ἶ'=>'I','Ἷ'=>'I',
'Ῐ'=>'I','Ῑ'=>'I','Ὶ'=>'I','Κ'=>'K','Λ'=>'L','Μ'=>'M',
'Ν'=>'N','Ξ'=>'K','Ο'=>'O','Ό'=>'O','Ὀ'=>'O','Ὁ'=>'O',
'Ὂ'=>'O','Ὃ'=>'O','Ὄ'=>'O','Ὅ'=>'O','Ὸ'=>'O','Π'=>'P',
'Ρ'=>'R','Ῥ'=>'R','Σ'=>'S','Τ'=>'T','Υ'=>'Y','Ύ'=>'Y',
'Ϋ'=>'Y','Ὑ'=>'Y','Ὓ'=>'Y','Ὕ'=>'Y','Ὗ'=>'Y','Ῠ'=>'Y',
'Ῡ'=>'Y','Ὺ'=>'Y','Φ'=>'F','Χ'=>'X','Ψ'=>'P','Ω'=>'O',
'Ώ'=>'O','Ὠ'=>'O','Ὡ'=>'O','Ὢ'=>'O','Ὣ'=>'O','Ὤ'=>'O',
'Ὥ'=>'O','Ὦ'=>'O','Ὧ'=>'O','ᾨ'=>'O','ᾩ'=>'O','ᾪ'=>'O',
'ᾫ'=>'O','ᾬ'=>'O','ᾭ'=>'O','ᾮ'=>'O','ᾯ'=>'O','Ὼ'=>'O',
'ῼ'=>'O','α'=>'a','ά'=>'a','ἀ'=>'a','ἁ'=>'a','ἂ'=>'a',
'ἃ'=>'a','ἄ'=>'a','ἅ'=>'a','ἆ'=>'a','ἇ'=>'a','ᾀ'=>'a',
'ᾁ'=>'a','ᾂ'=>'a','ᾃ'=>'a','ᾄ'=>'a','ᾅ'=>'a','ᾆ'=>'a',
'ᾇ'=>'a','ὰ'=>'a','ᾰ'=>'a','ᾱ'=>'a','ᾲ'=>'a','ᾳ'=>'a',
'ᾴ'=>'a','ᾶ'=>'a','ᾷ'=>'a','β'=>'b','γ'=>'g','δ'=>'d',
'ε'=>'e','έ'=>'e','ἐ'=>'e','ἑ'=>'e','ἒ'=>'e','ἓ'=>'e',
'ἔ'=>'e','ἕ'=>'e','ὲ'=>'e','ζ'=>'z','η'=>'i','ή'=>'i',
'ἠ'=>'i','ἡ'=>'i','ἢ'=>'i','ἣ'=>'i','ἤ'=>'i','ἥ'=>'i',
'ἦ'=>'i','ἧ'=>'i','ᾐ'=>'i','ᾑ'=>'i','ᾒ'=>'i','ᾓ'=>'i',
'ᾔ'=>'i','ᾕ'=>'i','ᾖ'=>'i','ᾗ'=>'i','ὴ'=>'i','ῂ'=>'i',
'ῃ'=>'i','ῄ'=>'i','ῆ'=>'i','ῇ'=>'i','θ'=>'t','ι'=>'i',
'ί'=>'i','ϊ'=>'i','ΐ'=>'i','ἰ'=>'i','ἱ'=>'i','ἲ'=>'i',
'ἳ'=>'i','ἴ'=>'i','ἵ'=>'i','ἶ'=>'i','ἷ'=>'i','ὶ'=>'i',
'ῐ'=>'i','ῑ'=>'i','ῒ'=>'i','ῖ'=>'i','ῗ'=>'i','κ'=>'k',
'λ'=>'l','μ'=>'m','ν'=>'n','ξ'=>'k','ο'=>'o','ό'=>'o',
'ὀ'=>'o','ὁ'=>'o','ὂ'=>'o','ὃ'=>'o','ὄ'=>'o','ὅ'=>'o',
'ὸ'=>'o','π'=>'p','ρ'=>'r','ῤ'=>'r','ῥ'=>'r','σ'=>'s',
'ς'=>'s','τ'=>'t','υ'=>'y','ύ'=>'y','ϋ'=>'y','ΰ'=>'y',
'ὐ'=>'y','ὑ'=>'y','ὒ'=>'y','ὓ'=>'y','ὔ'=>'y','ὕ'=>'y',
'ὖ'=>'y','ὗ'=>'y','ὺ'=>'y','ῠ'=>'y','ῡ'=>'y','ῢ'=>'y',
'ῦ'=>'y','ῧ'=>'y','φ'=>'f','χ'=>'x','ψ'=>'p','ω'=>'o',
'ώ'=>'o','ὠ'=>'o','ὡ'=>'o','ὢ'=>'o','ὣ'=>'o','ὤ'=>'o',
'ὥ'=>'o','ὦ'=>'o','ὧ'=>'o','ᾠ'=>'o','ᾡ'=>'o','ᾢ'=>'o',
'ᾣ'=>'o','ᾤ'=>'o','ᾥ'=>'o','ᾦ'=>'o','ᾧ'=>'o','ὼ'=>'o',
'ῲ'=>'o','ῳ'=>'o','ῴ'=>'o','ῶ'=>'o','ῷ'=>'o','А'=>'A',
'Б'=>'B','В'=>'V','Г'=>'G','Д'=>'D','Е'=>'E','Ё'=>'E',
'Ж'=>'Z','З'=>'Z','И'=>'I','Й'=>'I','К'=>'K','Л'=>'L',
'М'=>'M','Н'=>'N','О'=>'O','П'=>'P','Р'=>'R','С'=>'S',
'Т'=>'T','У'=>'U','Ф'=>'F','Х'=>'K','Ц'=>'T','Ч'=>'C',
'Ш'=>'S','Щ'=>'S','Ы'=>'Y','Э'=>'E','Ю'=>'Y','Я'=>'Y',
'а'=>'A','б'=>'B','в'=>'V','г'=>'G','д'=>'D','е'=>'E',
'ё'=>'E','ж'=>'Z','з'=>'Z','и'=>'I','й'=>'I','к'=>'K',
'л'=>'L','м'=>'M','н'=>'N','о'=>'O','п'=>'P','р'=>'R',
'с'=>'S','т'=>'T','у'=>'U','ф'=>'F','х'=>'K','ц'=>'T',
'ч'=>'C','ш'=>'S','щ'=>'S','ы'=>'Y','э'=>'E','ю'=>'Y',
'я'=>'Y','ð'=>'d','Ð'=>'D','þ'=>'t','Þ'=>'T','ა'=>'a',
'ბ'=>'b','გ'=>'g','დ'=>'d','ე'=>'e','ვ'=>'v','ზ'=>'z',
'თ'=>'t','ი'=>'i','კ'=>'k','ლ'=>'l','მ'=>'m','ნ'=>'n',
'ო'=>'o','პ'=>'p','ჟ'=>'z','რ'=>'r','ს'=>'s','ტ'=>'t',
'უ'=>'u','ფ'=>'p','ქ'=>'k','ღ'=>'g','ყ'=>'q','შ'=>'s',
'ჩ'=>'c','ც'=>'t','ძ'=>'d','წ'=>'t','ჭ'=>'c','ხ'=>'k',
'ჯ'=>'j','ჰ'=>'h','ʼ'=>"'",'̧' =>'', 'ḩ'=>'h','ʼ'=>"'",
'‘'=>"'",'’'=>"'",'ừ'=>'u','ế'=>'e','ả'=>'a','ị'=>'i',
'ậ'=>'a','ệ'=>'e','ỉ'=>'i','ộ'=>'o','ồ'=>'o','ề'=>'e',
'ơ'=>'o','ạ'=>'a','ẵ'=>'a','ư'=>'u','ắ'=>'a','ằ'=>'a',
'ầ'=>'a','ḑ'=>'d','Ḩ'=>'H','Ḑ'=>'D','ḑ'=>'d','ş'=>'s',
'ā'=>'a','ţ'=>'t'
);
return strtr( $input, $transliteration );
}
}
/**
* Get currency data from locale
*
* @param string Locale code, '#' - to use current currency
* @param string What return: 'code', 'symbol', 'ID'
* @return string|boolean Currency data depending on param $return OR FALSE on failed
*/
function locale_currency( $locale = '#', $return = 'code' )
{
global $current_locale;
if( $locale == '#' )
{ // Use current locale:
$locale = $current_locale;
}
// Extract country code from locale code:
$country_code = strtolower( substr( $locale, 3, 2 ) );
$CountryCache = & get_CountryCache();
if( ! ( $locale_Country = & $CountryCache->get_by_name( $country_code, false, false ) ) )
{ // Couldn't detect country by code:
return false;
}
if( ! ( $country_Currency = & $locale_Country->get_Currency() ) )
{ // Couldn't detect currency for the locale country:
return false;
}
// Return currency code depending on param $return:
switch( $return )
{
case 'symbol':
return $country_Currency->get( 'shortcut' );
case 'ID':
return $country_Currency->ID;
case 'code':
default:
return $country_Currency->get( 'code' );
}
}
?>