10 defined(
'JPATH_PLATFORM') or die;
32 protected static $languages = array();
40 protected $debug =
false;
48 protected $default =
'en-GB';
56 protected $orphans = array();
64 protected $metadata = null;
72 protected $locale = null;
80 protected $lang = null;
88 protected $paths = array();
96 protected $errorfiles = array();
104 protected $strings = array();
112 protected $used = array();
120 protected $counter = 0;
128 protected $override = array();
136 protected $transliterator = null;
144 protected $pluralSuffixesCallback = null;
152 protected $ignoredSearchWordsCallback = null;
160 protected $lowerLimitSearchWordCallback = null;
168 protected $upperLimitSearchWordCallback = null;
176 protected $searchDisplayedCharactersNumberCallback = null;
186 public function __construct($lang = null, $debug =
false)
188 $this->strings = array();
192 $lang = $this->default;
195 $this->setLanguage($lang);
196 $this->setDebug($debug);
198 $filename = JPATH_BASE .
"/language/overrides/$lang.override.ini";
200 if (file_exists($filename) && $contents = $this->parse($filename))
202 if (is_array($contents))
205 ksort($contents, SORT_STRING);
206 $this->
override = $contents;
213 $class = str_replace(
'-',
'_', $lang .
'Localise');
216 if (defined(
'JPATH_SITE'))
219 $paths[0] = JPATH_SITE .
"/language/overrides/$lang.localise.php";
220 $paths[2] = JPATH_SITE .
"/language/$lang/$lang.localise.php";
223 if (defined(
'JPATH_ADMINISTRATOR'))
226 $paths[1] = JPATH_ADMINISTRATOR .
"/language/overrides/$lang.localise.php";
227 $paths[3] = JPATH_ADMINISTRATOR .
"/language/$lang/$lang.localise.php";
231 $path = reset($paths);
233 while (!class_exists($class) && $path)
235 if (file_exists($path))
240 $path = next($paths);
243 if (class_exists($class))
253 if (method_exists($class,
'transliterate'))
255 $this->transliterator = array($class,
'transliterate');
258 if (method_exists($class,
'getPluralSuffixes'))
260 $this->pluralSuffixesCallback = array($class,
'getPluralSuffixes');
263 if (method_exists($class,
'getIgnoredSearchWords'))
265 $this->ignoredSearchWordsCallback = array($class,
'getIgnoredSearchWords');
268 if (method_exists($class,
'getLowerLimitSearchWord'))
270 $this->lowerLimitSearchWordCallback = array($class,
'getLowerLimitSearchWord');
273 if (method_exists($class,
'getUpperLimitSearchWord'))
275 $this->upperLimitSearchWordCallback = array($class,
'getUpperLimitSearchWord');
278 if (method_exists($class,
'getSearchDisplayedCharactersNumber'))
280 $this->searchDisplayedCharactersNumberCallback = array($class,
'getSearchDisplayedCharactersNumber');
297 public static function getInstance($lang, $debug =
false)
299 if (!isset(self::$languages[$lang . $debug]))
301 self::$languages[$lang . $debug] =
new JLanguage($lang, $debug);
304 return self::$languages[$lang . $debug];
320 public function _($string, $jsSafe =
false, $interpretBackSlashes =
true)
328 $key = strtoupper($string);
330 if (isset($this->strings[$key]))
332 $string = $this->debug ?
'**' . $this->strings[$key] .
'**' : $this->strings[$key];
337 $caller = $this->getCallerInfo();
339 if (!array_key_exists($key, $this->used))
341 $this->used[$key] = array();
344 $this->used[$key][] = $caller;
351 $caller = $this->getCallerInfo();
352 $caller[
'string'] = $string;
354 if (!array_key_exists($key, $this->orphans))
356 $this->orphans[$key] = array();
359 $this->orphans[$key][] = $caller;
361 $string =
'??' . $string .
'??';
368 $string = addslashes($string);
370 elseif ($interpretBackSlashes)
373 $string = str_replace(array(
'\\\\',
'\t',
'\n'), array(
"\\",
"\t",
"\n"), $string);
391 public function transliterate($string)
393 if ($this->transliterator !== null)
395 return call_user_func($this->transliterator, $string);
411 public function getTransliterator()
413 return $this->transliterator;
425 public function setTransliterator($function)
427 $previous = $this->transliterator;
428 $this->transliterator = $function;
442 public function getPluralSuffixes($count)
444 if ($this->pluralSuffixesCallback !== null)
446 return call_user_func($this->pluralSuffixesCallback, $count);
450 return array((
string) $count);
461 public function getPluralSuffixesCallback()
463 return $this->pluralSuffixesCallback;
475 public function setPluralSuffixesCallback($function)
477 $previous = $this->pluralSuffixesCallback;
478 $this->pluralSuffixesCallback = $function;
490 public function getIgnoredSearchWords()
492 if ($this->ignoredSearchWordsCallback !== null)
494 return call_user_func($this->ignoredSearchWordsCallback);
509 public function getIgnoredSearchWordsCallback()
511 return $this->ignoredSearchWordsCallback;
523 public function setIgnoredSearchWordsCallback($function)
525 $previous = $this->ignoredSearchWordsCallback;
526 $this->ignoredSearchWordsCallback = $function;
538 public function getLowerLimitSearchWord()
540 if ($this->lowerLimitSearchWordCallback !== null)
542 return call_user_func($this->lowerLimitSearchWordCallback);
557 public function getLowerLimitSearchWordCallback()
559 return $this->lowerLimitSearchWordCallback;
571 public function setLowerLimitSearchWordCallback($function)
573 $previous = $this->lowerLimitSearchWordCallback;
574 $this->lowerLimitSearchWordCallback = $function;
586 public function getUpperLimitSearchWord()
588 if ($this->upperLimitSearchWordCallback !== null)
590 return call_user_func($this->upperLimitSearchWordCallback);
605 public function getUpperLimitSearchWordCallback()
607 return $this->upperLimitSearchWordCallback;
619 public function setUpperLimitSearchWordCallback($function)
621 $previous = $this->upperLimitSearchWordCallback;
622 $this->upperLimitSearchWordCallback = $function;
634 public function getSearchDisplayedCharactersNumber()
636 if ($this->searchDisplayedCharactersNumberCallback !== null)
638 return call_user_func($this->searchDisplayedCharactersNumberCallback);
653 public function getSearchDisplayedCharactersNumberCallback()
655 return $this->searchDisplayedCharactersNumberCallback;
667 public function setSearchDisplayedCharactersNumberCallback($function)
669 $previous = $this->searchDisplayedCharactersNumberCallback;
670 $this->searchDisplayedCharactersNumberCallback = $function;
687 public static function exists($lang, $basePath = JPATH_BASE)
689 static $paths = array();
697 $path = $basePath .
'/language/' . $lang;
700 if (isset($paths[$path]))
702 return $paths[$path];
706 $paths[$path] = is_dir($path);
708 return $paths[$path];
724 public function load($extension =
'joomla', $basePath = JPATH_BASE, $lang = null, $reload =
false, $default =
true)
731 $path = self::getLanguagePath($basePath, $lang);
733 $internal = $extension ==
'joomla' || $extension ==
'';
734 $filename = $internal ? $lang : $lang .
'.' . $extension;
735 $filename =
"$path/$filename.ini";
737 if (isset($this->paths[$extension][$filename]) && !$reload)
740 $result = $this->paths[$extension][$filename];
745 $result = $this->loadLanguage($filename, $extension);
748 if ($result ===
false && $default)
751 $oldFilename = $filename;
754 $path = self::getLanguagePath($basePath, $this->
default);
755 $filename = $internal ? $this->
default : $this->
default .
'.' . $extension;
756 $filename =
"$path/$filename.ini";
759 if ($oldFilename != $filename)
761 $result = $this->loadLanguage($filename, $extension,
false);
782 protected function loadLanguage($filename, $extension =
'unknown')
789 if (file_exists($filename))
791 $strings = $this->parse($filename);
796 if (is_array($strings))
799 ksort($strings, SORT_STRING);
800 $this->strings = array_merge($this->strings, $strings);
803 if (is_array($strings) && count($strings))
806 $this->strings = array_merge($this->strings, $this->
override);
812 if (!isset($this->paths[$extension]))
814 $this->paths[$extension] = array();
817 $this->paths[$extension][$filename] = $result;
831 protected function parse($filename)
836 $php_errormsg = null;
837 $track_errors = ini_get(
'track_errors');
838 ini_set(
'track_errors',
true);
841 $contents = file_get_contents($filename);
842 $contents = str_replace(
'_QQ_',
'"\""', $contents);
843 $strings = @parse_ini_string($contents);
845 if (!is_array($strings))
853 ini_set(
'track_errors', $track_errors);
856 $blacklist = array(
'YES',
'NO',
'NULL',
'FALSE',
'ON',
'OFF',
'NONE',
'TRUE');
857 $regex =
'/^(|(\[[^\]]*\])|([A-Z][A-Z0-9_\-\.]*\s*=(\s*(("[^"]*")|(_QQ_)))+))\s*(;.*)?$/';
858 $this->debug =
false;
862 $file =
new SplFileObject($filename);
864 foreach ($file as $lineNumber => $line)
867 if ($lineNumber == 0)
869 $line = str_replace(
"\xEF\xBB\xBF",
'', $line);
873 $key = strtoupper(trim(substr($line, 0, strpos($line,
'='))));
876 $line = str_replace(
'\"',
'_QQ_', $line);
878 if (!preg_match($regex, $line) || in_array($key, $blacklist))
880 $errors[] = $lineNumber;
887 if (basename($filename) != $this->lang .
'.ini')
889 $this->errorfiles[$filename] = $filename .
JText::sprintf(
'JERROR_PARSING_LANGUAGE_FILE', implode(
', ', $errors));
893 $this->errorfiles[$filename] = $filename .
' : error(s) in line(s) ' . implode(
', ', $errors);
896 elseif ($php_errormsg)
899 $this->errorfiles[
'PHP' . $filename] =
'PHP parser errors :' . $php_errormsg;
918 public function get($property, $default = null)
920 if (isset($this->metadata[$property]))
922 return $this->metadata[$property];
935 protected function getCallerInfo()
938 if (!function_exists(
'debug_backtrace'))
943 $backtrace = debug_backtrace();
949 while ($continue && next($backtrace))
951 $step = current($backtrace);
952 $class = @ $step[
'class'];
955 if ($class !=
'JLanguage' && $class !=
'JText')
957 $info[
'function'] = @ $step[
'function'];
958 $info[
'class'] = $class;
959 $info[
'step'] = prev($backtrace);
962 $info[
'file'] = @ $step[
'file'];
963 $info[
'line'] = @ $step[
'line'];
979 public function getName()
981 return $this->metadata[
'name'];
993 public function getPaths($extension = null)
995 if (isset($extension))
997 if (isset($this->paths[$extension]))
999 return $this->paths[$extension];
1006 return $this->paths;
1017 public function getErrorFiles()
1019 return $this->errorfiles;
1029 public function getTag()
1031 return $this->metadata[
'tag'];
1041 public function isRTL()
1043 return (
bool) $this->metadata[
'rtl'];
1055 public function setDebug($debug)
1057 $previous = $this->debug;
1058 $this->debug = (boolean) $debug;
1070 public function getDebug()
1072 return $this->debug;
1082 public function getDefault()
1084 return $this->default;
1096 public function setDefault($lang)
1098 $previous = $this->default;
1099 $this->
default = $lang;
1111 public function getOrphans()
1113 return $this->orphans;
1125 public function getUsed()
1139 public function hasKey($string)
1141 $key = strtoupper($string);
1143 return isset($this->strings[$key]);
1155 public static function getMetadata($lang)
1157 $path = self::getLanguagePath(JPATH_BASE, $lang);
1158 $file = $lang .
'.xml';
1162 if (is_file(
"$path/$file"))
1164 $result = self::parseXMLLanguageFile(
"$path/$file");
1184 public static function getKnownLanguages($basePath = JPATH_BASE)
1186 $dir = self::getLanguagePath($basePath);
1187 $knownLanguages = self::parseLanguageFiles($dir);
1189 return $knownLanguages;
1202 public static function getLanguagePath($basePath = JPATH_BASE, $language = null)
1204 $dir = $basePath .
'/language';
1206 if (!empty($language))
1208 $dir .=
'/' . $language;
1225 public function setLanguage($lang)
1227 $previous = $this->lang;
1228 $this->lang = $lang;
1229 $this->metadata = $this->getMetadata($this->lang);
1241 public function getLocale()
1243 if (!isset($this->locale))
1245 $locale = str_replace(
' ',
'', isset($this->metadata[
'locale']) ? $this->metadata[
'locale'] :
'');
1249 $this->locale = explode(
',', $locale);
1253 $this->locale =
false;
1257 return $this->locale;
1267 public function getFirstDay()
1269 return (
int) (isset($this->metadata[
'firstDay']) ? $this->metadata[
'firstDay'] : 0);
1279 public function getWeekEnd()
1281 return (isset($this->metadata[
'weekEnd']) && $this->metadata[
'weekEnd']) ? $this->metadata[
'weekEnd'] :
'0,6';
1293 public static function parseLanguageFiles($dir = null)
1295 $languages = array();
1297 $iterator =
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir));
1299 foreach ($iterator as $file)
1302 $fileName = $file->getFilename();
1304 if (!$file->isFile() || !preg_match(
"/^([-_A-Za-z]*)\.xml$/", $fileName))
1311 $metadata = self::parseXMLLanguageFile($file->getRealPath());
1315 $lang = str_replace(
'.xml',
'', $fileName);
1316 $langs[$lang] = $metadata;
1319 $languages = array_merge($languages, $langs);
1321 catch (RuntimeException $e)
1339 public static function parseXMLLanguageFile($path)
1341 if (!is_readable($path))
1343 throw new RuntimeException(
'File not found or not readable');
1347 $xml = simplexml_load_file($path);
1355 if ((
string) $xml->getName() !=
'metafile')
1360 $metadata = array();
1362 foreach ($xml->metadata->children() as $child)
1364 $metadata[$child->getName()] = (string) $child;