]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/Localization/Localization.php
Release 6.2.4
[Github/sugarcrm.git] / include / Localization / Localization.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM Community Edition is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38 /*********************************************************************************
39
40  * Description:
41  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
42  * Reserved. Contributor(s): ______________________________________..
43  * *******************************************************************************/
44
45
46 class Localization {
47         var $availableCharsets = array(
48                 'BIG-5',        //Taiwan and Hong Kong
49                 /*'CP866'                         // ms-dos Cyrillic */
50                 /*'CP949'                         //Microsoft Korean */
51                 'CP1251',       //MS Cyrillic
52                 'CP1252',       //MS Western European & US
53                 'EUC-CN',       //Simplified Chinese GB2312
54                 'EUC-JP',       //Unix Japanese
55                 'EUC-KR',       //Korean
56                 'EUC-TW',       //Taiwanese
57                 'ISO-2022-JP',  //Japanese
58                 'ISO-2022-KR',  //Korean
59                 'ISO-8859-1',   //Western European and US
60                 'ISO-8859-2',   //Central and Eastern European
61                 'ISO-8859-3',   //Latin 3
62                 'ISO-8859-4',   //Latin 4
63                 'ISO-8859-5',   //Cyrillic
64                 'ISO-8859-6',   //Arabic
65                 'ISO-8859-7',   //Greek
66                 'ISO-8859-8',   //Hebrew
67                 'ISO-8859-9',   //Latin 5
68                 'ISO-8859-10',  //Latin 6
69                 'ISO-8859-13',  //Latin 7
70                 'ISO-8859-14',  //Latin 8
71                 'ISO-8859-15',  //Latin 9
72                 'KOI8-R',       //Cyrillic Russian
73                 'KOI8-U',       //Cyrillic Ukranian
74                 'SJIS',         //MS Japanese
75                 'UTF-8',        //UTF-8
76                 );
77         var $localeNameFormat;
78         var $localeNameFormatDefault;
79         var $default_export_charset = 'UTF-8';
80         var $default_email_charset = 'UTF-8';
81         var $currencies = array(); // array loaded with current currencies
82
83
84         /**
85          * sole constructor
86          */
87         function Localization() {
88                 global $sugar_config;
89                 $this->localeNameFormatDefault = empty($sugar_config['locale_name_format_default']) ? 's f l' : $sugar_config['default_name_format'];
90                 $this->loadCurrencies();
91         }
92
93         /**
94          * returns an array of Sugar Config defaults that are determined by locale settings
95          * @return array
96          */
97         function getLocaleConfigDefaults() {
98                 $coreDefaults = array(
99                         'currency'                                                              => '',
100                         'datef'                                                                 => 'm/d/Y',
101                         'timef'                                                                 => 'H:i',
102                         'default_currency_significant_digits'   => 2,
103                         'default_currency_symbol'                               => '$',
104                         'default_export_charset'                                => $this->default_export_charset,
105                         'default_locale_name_format'                    => 's f l',
106                         'default_number_grouping_seperator'             => ',',
107                         'default_decimal_seperator'                             => '.',
108                         'export_delimiter'                                              => ',',
109                         'default_email_charset'                                 => $this->default_email_charset,
110                 );
111
112                 return $coreDefaults;
113         }
114
115         /**
116          * abstraction of precedence
117          * @param string prefName Name of preference to retrieve based on overrides
118          * @param object user User in focus, default null (current_user)
119          * @return string pref Most significant preference
120          */
121         function getPrecedentPreference($prefName, $user=null, $sugarConfigPrefName = '') {
122                 global $current_user;
123                 global $sugar_config;
124
125                 $userPref = '';
126                 $coreDefaults = $this->getLocaleConfigDefaults();
127                 $pref = isset($coreDefaults[$prefName]) ? $coreDefaults[$prefName] : ''; // defaults, even before config.php
128
129                 if($user != null) {
130                         $userPref = $user->getPreference($prefName);
131                 } elseif(!empty($current_user)) {
132                         $userPref = $current_user->getPreference($prefName);
133                 }
134                 // Bug 39171 - If we are asking for default_email_charset, check in emailSettings['defaultOutboundCharset'] as well
135                 if ( $prefName == 'default_email_charset' ) {
136                     if($user != null) {
137                 $emailSettings = $user->getPreference('emailSettings', 'Emails');
138             } elseif(!empty($current_user)) {
139                 $emailSettings = $current_user->getPreference('emailSettings', 'Emails');
140             }
141             if ( isset($emailSettings['defaultOutboundCharset']) ) {
142                 $userPref = $emailSettings['defaultOutboundCharset'];
143             }
144                 }
145
146                 // set fallback defaults defined in this class
147                 if(isset($this->$prefName)) {
148                         $pref = $this->$prefName;
149                 }
150                 //rrs: 33086 - give the ability to pass in the preference name as stored in $sugar_config.
151                 if(!empty($sugarConfigPrefName)){
152                         $prefName = $sugarConfigPrefName;
153                 }
154                 // cn: 9549 empty() call on a value of 0 (0 significant digits) resulted in a false-positive.  changing to "isset()"
155                 $pref = (!isset($sugar_config[$prefName]) || (empty($sugar_config[$prefName]) && $sugar_config[$prefName] !== '0')) ? $pref : $sugar_config[$prefName];
156                 $pref = (empty($userPref) && $userPref !== '0') ? $pref : $userPref;
157                 return $pref;
158         }
159
160         ///////////////////////////////////////////////////////////////////////////
161         ////    CURRENCY HANDLING
162         /**
163          * wrapper for whatever currency system we implement
164          */
165         function loadCurrencies() {
166                 // doing it dirty here
167                 global $db;
168                 global $sugar_config;
169
170                 if(empty($db)) {
171                         return array();
172                 }
173
174         $load = sugar_cache_retrieve('currency_list');
175         if ( !is_array($load) ) {
176                         // load default from config.php
177                         $this->currencies['-99'] = array(
178                                 'name'          => $sugar_config['default_currency_name'],
179                                 'symbol'        => $sugar_config['default_currency_symbol'],
180                                 'conversion_rate' => 1
181                                 );
182
183             $q = "SELECT id, name, symbol, conversion_rate FROM currencies WHERE status = 'Active' and deleted = 0";
184             $r = $db->query($q);
185
186             while($a = $db->fetchByAssoc($r)) {
187                 $load = array();
188                 $load['name'] = $a['name'];
189                 $load['symbol'] = $a['symbol'];
190                 $load['conversion_rate'] = $a['conversion_rate'];
191
192                 $this->currencies[$a['id']] = $load;
193             }
194             sugar_cache_put('currency_list',$this->currencies);
195         } else {
196             $this->currencies = $load;
197         }
198
199                 
200         }
201
202         /**
203          * getter for currencies array
204          * @return array $this->currencies returns array( id => array(name => X, etc
205          */
206         function getCurrencies() {
207                 return $this->currencies;
208         }
209
210         /**
211          * retrieves default OOTB currencies for sugar_config and installer.
212          * @return array ret Array of default currencies keyed by ISO4217 code
213          */
214         function getDefaultCurrencies() {
215                 $ret = array(
216                         'AUD' => array( 'name'          => 'Australian Dollars',
217                                                         'iso4217'       => 'AUD',
218                                                         'symbol'        => '$'),
219                         'BRL' => array( 'name'          => 'Brazilian Reais',
220                                                         'iso4217'       => 'BRL',
221                                                         'symbol'        => 'R$'),
222                         'GBP' => array( 'name'          => 'British Pounds',
223                                                         'iso4217'       => 'GBP',
224                                                         'symbol'        => '£'),
225                         'CAD' => array( 'name'          => 'Canadian Dollars',
226                                                         'iso4217'       => 'CAD',
227                                                         'symbol'        => '$'),
228                         'CNY' => array( 'name'          => 'Chinese Yuan',
229                                                         'iso4217'       => 'CNY',
230                                                         'symbol'        => 'ï¿¥'),
231                         'EUR' => array( 'name'          => 'Euro',
232                                                         'iso4217'       => 'EUR',
233                                                         'symbol'        => '€'),
234                         'HKD' => array( 'name'          => 'Hong Kong Dollars',
235                                                         'iso4217'       => 'HKD',
236                                                         'symbol'        => '$'),
237                         'INR' => array( 'name'          => 'Indian Rupees',
238                                                         'iso4217'       => 'INR',
239                                                         'symbol'        => '₨'),
240                         'KRW' => array( 'name'          => 'Korean Won',
241                                                         'iso4217'       => 'KRW',
242                                                         'symbol'        => 'â‚©'),
243                         'YEN' => array( 'name'          => 'Japanese Yen',
244                                                         'iso4217'       => 'JPY',
245                                                         'symbol'        => 'Â¥'),
246                         'MXM' => array( 'name'          => 'Mexican Pesos',
247                                                         'iso4217'       => 'MXM',
248                                                         'symbol'        => '$'),
249                         'SGD' => array( 'name'          => 'Singaporean Dollars',
250                                                         'iso4217'       => 'SGD',
251                                                         'symbol'        => '$'),
252                         'CHF' => array( 'name'          => 'Swiss Franc',
253                                                         'iso4217'       => 'CHF',
254                                                         'symbol'        => 'SFr.'),
255                         'THB' => array( 'name'          => 'Thai Baht',
256                                                         'iso4217'       => 'THB',
257                                                         'symbol'        => '฿'),
258                         'USD' => array( 'name'          => 'US Dollars',
259                                                         'iso4217'       => 'USD',
260                                                         'symbol'        => '$'),
261                 );
262
263                 return $ret;
264         }
265         ////    END CURRENCY HANDLING
266         ///////////////////////////////////////////////////////////////////////////
267
268
269         ///////////////////////////////////////////////////////////////////////////
270         ////    CHARSET TRANSLATION
271         /**
272          * returns a mod|app_strings array in the target charset
273          * @param array strings $mod_string, et.al.
274          * @param string charset Target charset
275          * @return array Translated string pack
276          */
277         function translateStringPack($strings, $charset) {
278                 // handle recursive
279                 foreach($strings as $k => $v) {
280                         if(is_array($v)) {
281                                 $strings[$k] = $this->translateStringPack($v, $charset);
282                         } else {
283                                 $strings[$k] = $this->translateCharset($v, 'UTF-8', $charset);
284                         }
285                 }
286                 ksort($strings);
287                 return $strings;
288         }
289
290         /**
291          * translates the passed variable for email sending (export)
292          * @param       mixed the var (array or string) to translate
293          * @return      mixed the translated variable
294          */
295         function translateForEmail($var) {
296                 if(is_array($var)) {
297                         foreach($var as $k => $v) {
298                                 $var[$k] = $this->translateForEmail($v);
299                         }
300                         return $var;
301                 } elseif(!empty($var)) {
302                         return $this->translateCharset($var, 'UTF-8', $this->getOutboundEmailCharset());
303                 }
304         }
305
306         /**
307          * prepares a bean for export by translating any text fields into the export
308          * character set
309          * @param bean object A SugarBean
310          * @return bean object The bean with translated strings
311          */
312     function prepBeanForExport($bean) {
313         foreach($bean->field_defs as $k => $field) {
314                         $bean->$k = $this->translateCharset($bean->$k, 'UTF-8', $this->getExportCharset());
315         }
316
317         return $bean;
318     }
319
320         /**
321          * translates a character set from one encoding to another encoding
322          * @param string string the string to be translated
323          * @param string fromCharset the charset the string is currently in
324          * @param string toCharset the charset to translate into (defaults to UTF-8)
325          * @return string the translated string
326          */
327     function translateCharset($string, $fromCharset, $toCharset='UTF-8')
328     {
329         $GLOBALS['log']->debug("Localization: translating [ {$string} ] into {$toCharset}");
330
331         // Bug #35413 Function has to use iconv if $fromCharset is not in mb_list_encodings
332         $isMb = function_exists('mb_convert_encoding');
333         $isIconv = function_exists('iconv');
334         if ($isMb == true)
335         {
336             $fromCharset = strtoupper($fromCharset);
337             $listEncodings = mb_list_encodings();
338             $isFound = false;
339             foreach ($listEncodings as $encoding)
340             {
341                 if (strtoupper($encoding) == $fromCharset)
342                 {
343                     $isFound = true;
344                     break;
345                 }
346             }
347             $isMb = $isFound;
348         }
349
350         if($isMb)
351         {
352             return mb_convert_encoding($string, $toCharset, $fromCharset);
353         }
354         elseif($isIconv)
355         {
356             return iconv($fromCharset, $toCharset, $string);
357         }
358         else
359         {
360             return $string;
361         } // end else clause
362     }
363
364         /**
365          * translates a character set from one to another, and the into MIME-header friendly format
366          */
367         function translateCharsetMIME($string, $fromCharset, $toCharset='UTF-8', $encoding="Q") {
368                 $previousEncoding = mb_internal_encoding();
369             mb_internal_encoding($toCharset);
370                 $result = mb_encode_mimeheader($string, $toCharset, $encoding);
371                 mb_internal_encoding($previousEncoding);
372                 return $result;
373         }
374
375         function normalizeCharset($charset) {
376                 $charset = strtolower(preg_replace("/[\-\_]*/", "", $charset));
377                 return $charset;
378         }
379
380         /**
381          * returns an array of charsets with keys for available translations; appropriate for get_select_options_with_id()
382          */
383         function getCharsetSelect() {
384     //jc:12293 - the "labels" or "human-readable" representations of the various charsets
385     //should be translatable
386     $translated = array();
387     foreach($this->availableCharsets as $key)
388     {
389          //$translated[$key] = translate($value);
390          $translated[$key] = translate($key);
391     }
392
393                 return $translated;
394     //end:12293
395         }
396
397         /**
398          * returns the charset preferred in descending order: User, Sugar Config, DEFAULT
399          * @param string charset to override ALL, pass a valid charset here
400          * @return string charset the chosen character set
401          */
402         function getExportCharset($charset='', $user=null) {
403                 $charset = $this->getPrecedentPreference('default_export_charset', $user);
404                 return $charset;
405         }
406
407         /**
408          * returns the charset preferred in descending order: User, Sugar Config, DEFAULT
409          * @return string charset the chosen character set
410          */
411         function getOutboundEmailCharset($user=null) {
412                 $charset = $this->getPrecedentPreference('default_email_charset', $user);
413                 return $charset;
414         }
415         ////    END CHARSET TRANSLATION
416         ///////////////////////////////////////////////////////////////////////////
417
418         ///////////////////////////////////////////////////////////////////////////
419         ////    NUMBER DISPLAY FORMATTING CODE
420         function getDecimalSeparator($user=null) {
421                 $dec = $this->getPrecedentPreference('default_decimal_separator', $user);
422                 return $dec;
423         }
424
425         function getNumberGroupingSeparator($user=null) {
426                 $sep = $this->getPrecedentPreference('default_number_grouping_seperator', $user);
427                 return $sep;
428         }
429
430         function getPrecision($user=null) {
431                 $precision = $this->getPrecedentPreference('default_currency_significant_digits', $user);
432                 return $precision;
433         }
434
435         function getCurrencySymbol($user=null) {
436                 $dec = $this->getPrecedentPreference('default_currency_symbol', $user);
437                 return $dec;
438         }
439
440         /**
441          * returns a number formatted by user preference or system default
442          * @param string number Number to be formatted and returned
443          * @param string currencySymbol Currency symbol if override is necessary
444          * @param bool is_currency Flag to also return the currency symbol
445          * @return string Formatted number
446          */
447         function getLocaleFormattedNumber($number, $currencySymbol='', $is_currency=true, $user=null) {
448                 $fnum                   = $number;
449                 $majorDigits    = '';
450                 $minorDigits    = '';
451                 $dec                    = $this->getDecimalSeparator($user);
452                 $thou                   = $this->getNumberGroupingSeparator($user);
453                 $precision              = $this->getPrecision($user);
454                 $symbol                 = empty($currencySymbol) ? $this->getCurrencySymbol($user) : $currencySymbol;
455
456                 $exNum = explode($dec, $number);
457                 // handle grouping
458                 if(is_array($exNum) && count($exNum) > 0) {
459                         if(strlen($exNum[0]) > 3) {
460                                 $offset = strlen($exNum[0]) % 3;
461                                 if($offset > 0) {
462                                         for($i=0; $i<$offset; $i++) {
463                                                 $majorDigits .= $exNum[0]{$i};
464                                         }
465                                 }
466
467                                 $tic = 0;
468                                 for($i=$offset; $i<strlen($exNum[0]); $i++) {
469                                         if($tic % 3 == 0 && $i != 0) {
470                                                 $majorDigits .= $thou; // add separator
471                                         }
472
473                                         $majorDigits .= $exNum[0]{$i};
474                                         $tic++;
475                                 }
476                         } else {
477                                 $majorDigits = $exNum[0]; // no formatting needed
478                         }
479                         $fnum = $majorDigits;
480                 }
481
482                 // handle decimals
483                 if($precision > 0) { // we toss the minor digits otherwise
484                         if(is_array($exNum) && isset($exNum[1])) {
485
486                         }
487                 }
488
489
490                 if($is_currency) {
491                         $fnum = $symbol.$fnum;
492                 }
493                 return $fnum;
494         }
495
496         /**
497          * returns Javascript to format numbers and currency for ***DISPLAY***
498          */
499         function getNumberJs() {
500                 $out = <<<eoq
501
502                         var exampleDigits = '123456789.000000';
503
504                         // round parameter can be negative for decimal, precision has to be postive
505                         function formatNumber(n, sep, dec, precision) {
506                                 var majorDigits;
507                                 var minorDigits;
508                                 var formattedMajor = '';
509                                 var formattedMinor = '';
510
511                                 var nArray = n.split('.');
512                                 majorDigits = nArray[0];
513                                 if(nArray.length < 2) {
514                                         minorDigits = 0;
515                                 } else {
516                                         minorDigits = nArray[1];
517                                 }
518
519                                 // handle grouping
520                                 if(sep.length > 0) {
521                                         var strlength = majorDigits.length;
522
523                                         if(strlength > 3) {
524                                                 var offset = strlength % 3; // find how many to lead off by
525
526                                                 for(j=0; j<offset; j++) {
527                                                         formattedMajor += majorDigits[j];
528                                                 }
529
530                                                 tic=0;
531                                                 for(i=offset; i<strlength; i++) {
532                                                         if(tic % 3 == 0 && i != 0)
533                                                                 formattedMajor += sep;
534
535                                                         formattedMajor += majorDigits.substr(i,1);
536                                                         tic++;
537                                                 }
538                                         }
539                                 } else {
540                                         formattedMajor = majorDigits; // no grouping marker
541                                 }
542
543                                 // handle decimal precision
544                                 if(precision > 0) {
545                                         for(i=0; i<precision; i++) {
546                                                 if(minorDigits[i] != undefined)
547                                                         formattedMinor += minorDigits[i];
548                                                 else
549                                                         formattedMinor += '0';
550                                         }
551                                 } else {
552                                         // we're just returning the major digits, no decimal marker
553                                         dec = ''; // just in case
554                                 }
555
556                                 return formattedMajor + dec + formattedMinor;
557                         }
558
559                         function setSigDigits() {
560                                 var sym = document.getElementById('symbol').value;
561                                 var thou = document.getElementById('default_number_grouping_seperator').value;
562                                 var dec = document.getElementById('default_decimal_seperator').value;
563                                 var precision = document.getElementById('sigDigits').value;
564                                 //umber(n, num_grp_sep, dec_sep, round, precision)
565                                 var newNumber = sym + formatNumber(exampleDigits, thou, dec, precision, precision);
566                                 document.getElementById('sigDigitsExample').value = newNumber;
567                         }
568 eoq;
569                 return $out;
570         }
571
572         ////    END NUMBER DISPLAY FORMATTING CODE
573         ///////////////////////////////////////////////////////////////////////////
574
575         ///////////////////////////////////////////////////////////////////////////
576         ////    NAME DISPLAY FORMATTING CODE
577         /**
578          * get's the Name format macro string, preferring $current_user
579          * @return string format Name Format macro for locale
580          */
581         function getLocaleFormatMacro($user=null) {
582                 $returnFormat = $this->getPrecedentPreference('default_locale_name_format', $user);
583                 return $returnFormat;
584         }
585
586         /**
587          * returns formatted name according to $current_user's locale settings
588          *
589          * @param string firstName
590          * @param string lastName
591          * @param string salutation
592          * @param string title
593          * @param string format If a particular format is desired, then pass this optional parameter as a simple string.
594          * sfl is "Salutation FirstName LastName", "l, f s" is "LastName[comma][space]FirstName[space]Salutation"
595          * @param object user object
596          * @param bool returnEmptyStringIfEmpty true if we should return back an empty string rather than a single space
597          * when the formatted name would be blank
598          * @return string formattedName
599          */
600         function getLocaleFormattedName($firstName, $lastName, $salutationKey='', $title='', $format="", $user=null, $returnEmptyStringIfEmpty = false) {
601                 global $current_user;
602                 global $app_list_strings;
603
604                 if ( $user == null ) {
605                     $user = $current_user;
606                 }
607
608                 $salutation = $salutationKey;
609                 if(!empty($salutationKey) && !empty($app_list_strings['salutation_dom'][$salutationKey])) {
610                         $salutation = (!empty($app_list_strings['salutation_dom'][$salutationKey]) ? $app_list_strings['salutation_dom'][$salutationKey] : $salutationKey);
611                 }
612
613         //check to see if passed in variables are set, if so, then populate array with value,
614         //if not, then populate array with blank ''
615                 $names = array();
616                 $names['f'] = (empty($firstName)        && $firstName   != 0) ? '' : $firstName;
617                 $names['l'] = (empty($lastName) && $lastName    != 0) ? '' : $lastName;
618                 $names['s'] = (empty($salutation)       && $salutation  != 0) ? '' : $salutation;
619                 $names['t'] = (empty($title)            && $title               != 0) ? '' : $title;
620
621                 //Bug: 39936 - if all of the inputs are empty, then don't try to format the name.
622                 $allEmpty = true;
623                 foreach($names as $key => $val){
624                         if(!empty($val)){
625                                 $allEmpty = false;
626                                 break;
627                         }
628                 }
629                 if($allEmpty){
630                         return $returnEmptyStringIfEmpty ? '' : ' ';
631                 }
632                 //end Bug: 39936
633
634                 if(empty($format)) {
635                         $this->localeNameFormat = $this->getLocaleFormatMacro($user);
636                 } else {
637                         $this->localeNameFormat = $format;
638                 }
639
640                 // parse localeNameFormat
641                 $formattedName = '';
642                 for($i=0; $i<strlen($this->localeNameFormat); $i++) {
643                         $formattedName .= array_key_exists($this->localeNameFormat{$i}, $names) ? $names[$this->localeNameFormat{$i}] : $this->localeNameFormat{$i};
644                 }
645
646                 $formattedName = trim($formattedName);
647         if (strlen($formattedName)==0) {
648             return $returnEmptyStringIfEmpty ? '' : ' ';
649         }
650
651                 if(strpos($formattedName,',',strlen($formattedName)-1)) { // remove trailing commas
652                         $formattedName = substr($formattedName, 0, strlen($formattedName)-1);
653                 }
654                 return trim($formattedName);
655         }
656
657         /**
658          * outputs some simple Javascript to show a preview of Name format in "My Account" and "Admin->Localization"
659          * @param string first First Name, use app_strings default if not specified
660          * @param string last Last Name, use app_strings default if not specified
661          * @param string salutation Saluation, use app_strings default if not specified
662          * @return string some Javascript
663          */
664         function getNameJs($first='', $last='', $salutation='', $title='') {
665                 global $app_strings;
666
667                 $salutation     = !empty($salutation) ? $salutation : $app_strings['LBL_LOCALE_NAME_EXAMPLE_SALUTATION'];
668                 $first          = !empty($first) ? $first : $app_strings['LBL_LOCALE_NAME_EXAMPLE_FIRST'];
669                 $last           = !empty($last) ? $last : $app_strings['LBL_LOCALE_NAME_EXAMPLE_LAST'];
670                 $title          = !empty($title) ? $title : $app_strings['LBL_LOCALE_NAME_EXAMPLE_TITLE'];
671
672                 $ret = "
673                 function setPreview() {
674                         format = document.getElementById('default_locale_name_format').value;
675                         field = document.getElementById('nameTarget');
676
677                         stuff = new Object();
678
679                         stuff['s'] = '{$salutation}';
680                         stuff['f'] = '{$first}';
681                         stuff['l'] = '{$last}';
682                         stuff['t'] = '{$title}';
683
684                         var name = '';
685                         for(i=0; i<format.length; i++) {
686                 if(stuff[format.substr(i,1)] != undefined) {
687                     name += stuff[format.substr(i,1)];
688                                 } else {
689                     name += format.substr(i,1);
690                                 }
691                         }
692
693                         //alert(name);
694                         field.value = name;
695                 }
696
697         ";
698
699                 return $ret;
700         }
701         ////    END NAME DISPLAY FORMATTING CODE
702         ///////////////////////////////////////////////////////////////////////////
703
704     /**
705      * Attempts to detect the charset used in the string
706      *
707      * @param  $str string
708      * @return string
709      */
710     public function detectCharset(
711         $str
712         )
713     {
714         if ( function_exists('mb_convert_encoding') )
715             return mb_detect_encoding($str,'ASCII,JIS,UTF-8,EUC-JP,SJIS,ISO-8859-1');
716
717         return false;
718     }
719 } // end class def
720
721 ?>