libretime/htmlUI/localizer/Localizer.php

647 lines
20 KiB
PHP

<?php
/**
* This file would normally be split into multiple files but since it must
* be fast (it gets loaded for every hit to the admin screen), we put it
* all in one file.
*/
/**
* Includes
*/
require_once 'File.php';
require_once 'File/Find.php';
require_once dirname(__FILE__).'/LocalizerConfig.php';
require_once dirname(__FILE__).'/LocalizerLanguage.php';
require_once dirname(__FILE__).'/LanguageMetadata.php';
/**
* Translate the given string and print it. This function accepts a variable
* number of parameters and works something like printf().
*
* @param string $p_translateString
* The string to translate.
*
* @return void
*/
function putGS($p_translateString)
{
$args = func_get_args();
echo call_user_func_array('getGS', $args);
} // fn putGS
/**
* Translate the given string and return it. This function accepts a variable
* number of parameters and works something like printf().
*
* @param string $p_translateString -
* The string to translate.
*
* @return string
*/
function getGS($p_translateString)
{
global $g_translationStrings, $TOL_Language;
$numFunctionArgs = func_num_args();
if (!isset($g_translationStrings[$p_translateString]) || ($g_translationStrings[$p_translateString]=='')) {
$translatedString = "$p_translateString (*)";
}
else {
$translatedString = $g_translationStrings[$p_translateString];
}
if ($numFunctionArgs > 1) {
for ($i = 1; $i < $numFunctionArgs; $i++){
$name = '$'.$i;
$val = func_get_arg($i);
$translatedString = str_replace($name, $val, $translatedString);
}
}
return $translatedString;
} // fn getGS
/**
* Register a string in the global translation file. (Legacy code for GS files)
*
* @param string $p_value
* @param string $p_key
* @return void
*/
function regGS($p_key, $p_value)
{
global $g_translationStrings;
if (isset($g_translationStrings[$p_key])) {
if ($p_key!='') {
print "The global string is already set in ".$_SERVER[PHP_SELF].": $key<BR>";
}
}
else{
if (substr($p_value, strlen($p_value)-3)==(":".$_REQUEST["TOL_Language"])){
$p_value = substr($p_value, 0, strlen($p_value)-3);
}
$g_translationStrings[$p_key] = $p_value;
}
} // fn regGS
/**
* The Localizer class handles groups of translation tables (LocalizerLanguages).
* This class simply acts as a namespace for a group of static methods.
*/
class Localizer {
/**
* Return the type of files we are currently using, currently
* either 'gs' or 'xml'. If not set in the config file, we will
* do our best to figure out the current mode.
*
* @return mixed
* Will return 'gs' or 'xml' on success, or NULL on failure.
*/
function GetMode()
{
global $g_localizerConfig;
if ($g_localizerConfig['DEFAULT_FILE_TYPE'] != '') {
return $g_localizerConfig['DEFAULT_FILE_TYPE'];
}
$defaultLang = new LocalizerLanguage('globals',
$g_localizerConfig['DEFAULT_LANGUAGE']);
if ($defaultLang->loadGsFile()) {
return 'gs';
}
elseif ($defaultLang->loadXmlFile()) {
return 'xml';
}
else {
return null;
}
} // fn GetMode
/**
* Load the translation strings into a global variable and return them.
*
* @param string $p_prefix -
* Beginning of the file name, before the ".php" extension.
* @param string $p_languageCode
* id of language to load
* @param bool $p_return
* return translation array
*
* @return void
*/
function LoadLanguageFiles($p_prefix, $p_languageCode = null, $p_return = false)
{
global $g_localizerConfig;
if ($p_return) {
static $g_translationStrings;
} else {
global $g_translationStrings;
}
if (is_null($p_languageCode)){
$p_languageCode = $g_localizerConfig['DEFAULT_LANGUAGE'];
}
if (!isset($g_translationStrings)) {
$g_translationStrings = array();
}
$key = $p_prefix."_".$g_localizerConfig['DEFAULT_LANGUAGE'];
if (!isset($g_localizerConfig['LOADED_FILES'][$key])) {
$defaultLang = new LocalizerLanguage($p_prefix, $g_localizerConfig['DEFAULT_LANGUAGE']);
$defaultLang->loadFile(Localizer::GetMode());
$defaultLangStrings = $defaultLang->getTranslationTable();
// Merge default language strings into the translation array.
#$g_translationStrings = array_merge($g_translationStrings, $defaultLangStrings);
$g_translationStrings = Localizer::_arrayValuesMerge($g_translationStrings, $defaultLangStrings);
$g_localizerConfig['LOADED_FILES'][$key] = true;
}
$key = $p_prefix."_".$p_languageCode;
if (!isset($g_localizerConfig['LOADED_FILES'][$key])) {
$userLang = new LocalizerLanguage($p_prefix, $p_languageCode);
$userLang->loadFile(Localizer::GetMode());
$userLangStrings = $userLang->getTranslationTable();
// Merge user strings into translation array.
#$g_translationStrings = array_merge($g_translationStrings, $userLangStrings);
$g_translationStrings = Localizer::_arrayValuesMerge($g_translationStrings, $userLangStrings);
$g_localizerConfig['LOADED_FILES'][$key] = true;
}
if ($p_return) {
return $g_translationStrings;
}
} // fn LoadLanguageFiles
function _arrayValuesMerge($arr1, $arr2)
{
foreach ($arr2 as $k=>$v) {
if (strlen($v)) {
$arr1[$k] = $v;
}
}
return $arr1;
}
/**
* Compare a particular language's keys with the default language set.
*
* @param string $p_prefix -
* The prefix of the language files.
*
* @param array $p_data -
* A set of keys.
*
* @param boolean $p_findExistingKeys -
* Set this to true to return the set of keys (of the keys given) that already exist,
* set this to false to return the set of keys (of the keys given) that do not exist.
*
* @return array
*/
function CompareKeys($p_prefix, $p_data, $p_findExistingKeys = true)
{
global $g_localizerConfig;
$localData = new LocalizerLanguage($p_prefix,
$g_localizerConfig['DEFAULT_LANGUAGE']);
$localData->loadFile(Localizer::GetMode());
$globaldata = new LocalizerLanguage($g_localizerConfig['FILENAME_PREFIX_GLOBAL'],
$g_localizerConfig['DEFAULT_LANGUAGE']);
$globaldata->loadFile(Localizer::GetMode());
$returnValue = array();
foreach ($p_data as $key) {
$globalKeyExists = $globaldata->keyExists($key);
$localKeyExists = $localData->keyExists($key);
if ($p_findExistingKeys && ($globalKeyExists || $localKeyExists)) {
$returnValue[$key] = $key;
}
elseif (!$p_findExistingKeys && !$globalKeyExists && !$localKeyExists) {
$returnValue[$key] = $key;
}
}
return $returnValue;
} // fn CompareKeys
/**
* Search through PHP files and find all the strings that need to be translated.
* @param string $p_directory -
* @return array
*/
function FindTranslationStrings($p_prefix, $p_depth=0)
{
global $g_localizerConfig;
//Start search here
$dir = $g_localizerConfig["mapPrefixToDir"][$p_prefix]['path'];
$depth = $g_localizerConfig["mapPrefixToDir"][$p_prefix]['depth'];
// Scan which files
$filePatterns = $g_localizerConfig['mapPrefixToDir'][$p_prefix]['filePatterns'];
$execludePattern = $g_localizerConfig['mapPrefixToDir'][$p_prefix]['execlPattern'];
if ($g_localizerConfig['DEBUG']) echo "<br>Scan files match ".print_r($filePatterns, 1);
// Scan for what
$funcPatterns = $g_localizerConfig['mapPrefixToDir'][$p_prefix]['funcPatterns'];
if ($g_localizerConfig['DEBUG']) echo "<br>Scan for ".print_r($funcPatterns, 1);
// Get all files in this directory
if ($g_localizerConfig['DEBUG']) echo "<br>Search in: {$g_localizerConfig['BASE_DIR']}$dir Depth: {$depth}";
$files = File_Find::mapTreeMultiple($g_localizerConfig['BASE_DIR'].$dir, $depth);
$files = Localizer::_flatFileList($files);
#print_r($files);
// Get all the Matching files
foreach ($filePatterns as $fp) {
foreach ($files as $name) {
if (preg_match($fp, $name) && !preg_match($execludePattern, $name)) {
$filelist[] = $name;
}
}
reset($files);
}
#print_r($filelist);
// Read in all the PHP files.
$data = array();
foreach ($filelist as $name) {
$data = array_merge($data, file($g_localizerConfig['BASE_DIR'].$dir.'/'.$name));
}
#print_r($data);
// Collect all matches
$matches = array();
foreach ($data as $line) {
foreach ($funcPatterns as $fp => $pos) {
if (preg_match_all($fp, $line, $m)) {
foreach ($m[$pos] as $match) {
#$match = str_replace("\\\\", "\\", $match);
if (strlen($match)) $matches[$match] = $match;
}
}
}
reset($funcPatterns);
}
asort($matches);
#print_r($matches);
return $matches;
} // fn FindTranslationStrings
function _flatFileList($files, $appdir='', $init=TRUE)
{
static $_flatList;
if ($init === TRUE) $_flatList = array();
foreach ($files as $dir => $name) {
if (is_array($name)) {
Localizer::_flatFileList($name, $appdir.'/'.$dir, FALSE);
} else {
$_flatList[] = $appdir.'/'.$name;
}
}
return $_flatList;
}
/**
* Return the set of strings in the code that are not in the translation files.
* @param string $p_directory -
* @return array
*/
function FindMissingStrings($p_prefix)
{
global $g_localizerConfig;
if (empty($p_prefix)) {
return array();
}
$newKeys =& Localizer::FindTranslationStrings($p_prefix);
$missingKeys =& Localizer::CompareKeys($p_prefix, $newKeys, false);
$missingKeys = array_unique($missingKeys);
return $missingKeys;
} // fn FindMissingStrings
/**
* Return the set of strings in the translation files that are not used in the code.
* @param string $p_prefix
* @param string $p_directory -
* @return array
*/
function FindUnusedStrings($p_prefix)
{
global $g_localizerConfig;
if (empty($p_prefix)) {
return array();
}
$existingKeys =& Localizer::FindTranslationStrings($p_prefix);
$localData = new LocalizerLanguage($p_prefix, $g_localizerConfig['DEFAULT_LANGUAGE']);
$localData->loadFile(Localizer::GetMode());
$localTable = $localData->getTranslationTable();
$unusedKeys = array();
foreach ($localTable as $key => $value) {
if (!in_array($key, $existingKeys)) {
$unusedKeys[$key] = $key;
}
}
$unusedKeys = array_unique($unusedKeys);
return $unusedKeys;
} // fn FindUnusedStrings
/**
* Update a set of strings in a language file.
* @param string $p_prefix
* @param string $p_languageCode
* @param array $p_data
*
* @return void
*/
function ModifyStrings($p_prefix, $p_languageId, $p_data)
{
global $g_localizerConfig;
// If we change a string in the default language,
// then all the language files must be updated with the new key.
if ($p_languageId == $g_localizerConfig['DEFAULT_LANGUAGE']) {
$languages = Localizer::GetAllLanguages();
foreach ($languages as $language) {
// Load the language file
$source = new LocalizerLanguage($p_prefix, $language->getLanguageId());
$source->loadFile(Localizer::GetMode());
// For the default language, we set the key & value to be the same.
if ($p_languageId == $language->getLanguageId()) {
foreach ($p_data as $pair) {
$source->updateString($pair['key'], $pair['value'], $pair['value']);
}
}
// For all other languages, we just change the key and keep the old value.
else {
foreach ($p_data as $pair) {
$source->updateString($pair['key'], $pair['value']);
}
}
// Save the file
$source->saveFile(Localizer::GetMode());
}
}
// We only need to change the values in one file.
else {
// Load the language file
$source = new LocalizerLanguage($p_prefix, $p_languageId);
$source->loadFile(Localizer::GetMode());
foreach ($p_data as $pair) {
$source->updateString($pair['key'], $pair['key'], $pair['value']);
}
// Save the file
$source->saveFile(Localizer::GetMode());
}
} // fn ModifyStrings
/**
* Synchronize the positions of the strings to the default language file order.
* @param string $p_prefix
* @return void
*/
function FixPositions($p_prefix)
{
global $g_localizerConfig;
$defaultLanguage = new LocalizerLanguage($p_prefix, $g_localizerConfig['DEFAULT_LANGUAGE']);
$defaultLanguage->loadFile(Localizer::GetMode());
$defaultTranslationTable = $defaultLanguage->getTranslationTable();
$languageIds = Localizer::GetAllLanguages();
foreach ($languageIds as $languageId) {
// Load the language file
$source = new LocalizerLanguage($p_prefix, $languageId);
$source->loadFile(Localizer::GetMode());
$count = 0;
foreach ($defaultTranslationTable as $key => $value) {
$source->moveString($key, $count);
$count++;
}
// Save the file
$source->saveFile(Localizer::GetMode());
}
} // fn FixPositions
/**
* Go through all files matching $p_prefix in $p_directory and add entry(s).
*
* @param string $p_prefix
* @param int $p_position
* @param array $p_newKey
*
* @return void
*/
function AddStringAtPosition($p_prefix, $p_position, $p_newKey)
{
global $g_localizerConfig;
$languages = Localizer::GetAllLanguages();
foreach ($languages as $language) {
$source = new LocalizerLanguage($p_prefix, $language->getLanguageId());
$source->loadFile(Localizer::GetMode());
if (is_array($p_newKey)) {
foreach (array_reverse($p_newKey) as $key) {
if ($language->getLanguageId() == $g_localizerConfig['DEFAULT_LANGUAGE']) {
$source->addString($key, $key, $p_position);
}
else {
$source->addString($key, '', $p_position);
}
}
}
else {
if ($Id == $g_localizerConfig['DEFAULT_LANGUAGE']) {
$source->addString($p_newKey, $p_newKey, $p_position);
}
else {
$source->addString($p_newKey, '', $p_position);
}
}
$source->saveFile(Localizer::GetMode());
}
} // fn AddStringAtPosition
/**
* Go through all files matching $p_prefix remove selected entry.
* @param string $p_prefix
* @param mixed $p_key -
* Can be a string or an array of strings.
* @return void
*/
function RemoveString($p_prefix, $p_key)
{
$languages = Localizer::GetAllLanguages();
foreach ($languages as $language) {
$target = new LocalizerLanguage($p_prefix, $language->getLanguageId());
$target->loadFile(Localizer::GetMode());
if (is_array($p_key)) {
foreach ($p_key as $key) {
$target->deleteString($key);
}
}
else {
$target->deleteString($p_key);
}
$target->saveFile(Localizer::GetMode());
}
} // fn RemoveString
/**
* Go through all files matching $p_prefix swap selected entrys.
*
* @param string $p_prefix
* @param int $p_pos1
* @param int $p_pos2
*
* @return void
*/
function MoveString($p_prefix, $p_pos1, $p_pos2)
{
$languages = Localizer::GetAllLanguages();
foreach ($languages as $language) {
$target = new LocalizerLanguage($p_prefix, $language->getLanguageId());
$target->loadFile(Localizer::GetMode());
$success = $target->moveString($p_pos1, $p_pos2);
$target->saveFile(Localizer::GetMode());
}
} // fn MoveString
/**
* Get all the languages that the interface supports.
*
* When in PHP mode, it will get the list from the database.
* When in XML mode, it will first try to look in the languages.xml file located
* in the current directory, and if it doesnt find that, it will look at the file names
* in the top directory and deduce the languages from that.
*
* @param string $p_mode
* @return array
* An array of LanguageMetadata objects.
*/
function GetAllLanguages($p_mode = null, $p_default=TRUE, $p_completed_only=FALSE)
{
if (is_null($p_mode)) {
$p_mode = Localizer::GetMode();
}
$className = "LocalizerFileFormat_".strtoupper($p_mode);
if (class_exists($className)) {
$object = new $className();
if (method_exists($object, "getLanguages")) {
$languages = $object->getLanguages($p_default, $p_completed_only);
}
}
//$this->m_languageDefs =& $languages;
return $languages;
} // fn GetAllLanguages
/**
* Get a list of all files matching the pattern given.
* Return an array of strings, each the full path name of a file.
* @param string $p_startdir
* @param string $p_pattern
* @return array
*/
function SearchFilesRecursive($p_startdir, $p_pattern)
{
$structure = File_Find::mapTreeMultiple($p_startdir);
// Transform it into a flat structure.
$filelist = array();
foreach ($structure as $dir => $file) {
// it's a directory
if (is_array($file)) {
$filelist = array_merge($filelist,
Localizer::SearchFilesRecursive($p_startdir.'/'.$dir, $p_pattern));
}
else {
// it's a file
if (preg_match($p_pattern, $file)) {
$filelist[] = $p_startdir.'/'.$file;
}
}
}
return $filelist;
} // fn SearchFilesRecursive
/**
* Create a new directory and make a copy of current default language files.
* @param string $p_languageId
* @return void
*/
function CreateLanguageFiles($p_languageId)
{
global $g_localizerConfig;
// Make new directory
if (!mkdir($g_localizerConfig['TRANSLATION_DIR']."/".$p_languageId)) {
return;
}
// Copy files from reference language
// $className = "LocalizerFileFormat_".strtoupper(Localizer::GetMode());
// foreach ($files as $pathname) {
// if ($pathname) {
// $fileNameParts = explode('.', basename($pathname));
// $base = $fileNameParts[0];
// $dir = str_replace($g_localizerConfig['BASE_DIR'], '', dirname($pathname));
// // read the default file
// $defaultLang = new LocalizerLanguage($base, $g_localizerConfig['DEFAULT_LANGUAGE']);
// $defaultLang->loadFile(Localizer::GetMode());
// $defaultLang->clearValues();
// $defaultLang->setLanguageId($p_languageId);
// // if file already exists -> skip
// if (!file_exists($defaultLang->getFilePath())) {
// $defaultLang->saveFile(Localizer::GetMode());
// }
// }
// }
} // fn CreateLanguageFiles
/**
* Go through subdirectorys and delete language files for given Id.
* @param string $p_languageId
* @return void
*/
function DeleteLanguageFiles($p_languageId)
{
global $g_localizerConfig;
$langDir = $g_localizerConfig['TRANSLATION_DIR'].'/'.$p_languageId;
if (!file_exists($langDir)) {
return;
}
$files = File_Find::mapTreeMultiple($langDir, 1);
//echo "<pre>";print_r($files);echo "</pre>";
foreach ($files as $pathname) {
if (file_exists($pathname)) {
echo 'deleteing '.$pathname.'<br>';
//unlink($pathname);
}
}
} // fn DeleteLanguageFiles
} // class Localizer
?>