libretime/htmlUI/localizer/LocalizerLanguage.php

670 lines
18 KiB
PHP

<?PHP
/**
* Includes
*/
require_once 'PEAR.php';
require_once dirname(__FILE__).'/LocalizerConfig.php';
require_once dirname(__FILE__).'/LocalizerFileFormat.php';
class LocalizerLanguage {
var $m_translationTable = array();
var $m_languageCode = '';
var $m_countryCode = '';
var $m_languageId = '';
var $m_mode = '';
var $m_prefix = '';
var $m_filePath = '';
/**
* A LocalizerLanguage is basically a translation table.
*
* You can use this class to manipulate the translation table:
* such as add, delete, and move strings.
*
* @param string $p_prefix
* The beginning of the file name, up to the first dot ('.').
*
* @param string $p_directory
* The location of the language file, relative to LOCALIZER_BASE_DIR.
*
* @param string $p_languageId
* The language ID for this language, which can be in one of two forms:
* 1) The two-letter language code (e.g. "en").
* 2) The two-letter language code, underscore, two-letter country code
* (e.g. "en_US")
*/
function LocalizerLanguage($p_prefix, $p_languageId = null)
{
if (!is_null($p_languageId)) {
$this->setLanguageId($p_languageId);
}
$this->m_prefix = $p_prefix;
} // constructor
/**
* Return the filename prefix.
* @return string
*/
function getPrefix()
{
return $this->m_prefix;
} // fn getPrefix
/**
* This will return 'gs' or 'xml'
* @return string
*/
function getMode()
{
return $this->m_mode;
} // fn getMode
/**
* Set the mode to be 'xml' or 'gs'.
* @param string $p_value
* @return void
*/
function setMode($p_value)
{
$p_value = strtolower($p_value);
if (($p_value == 'xml') || ($p_value == 'gs')) {
$this->m_mode = $p_value;
}
} // fn setMode
/**
* Set the language code - this can take either the two-letter language code
* or the LL_CC extended version , where LL is the language code and CC
* is the country code.
*
* @param string $p_languageId
* @return void
*/
function setLanguageId($p_languageId)
{
if (strlen($p_languageId) > 2) {
list ($this->m_languageCode, $this->m_countryCode) = explode('_', $p_languageId);
$this->m_languageId = $p_languageId;
}
else {
$this->m_languageCode = $p_languageId;
$this->m_languageId = $p_languageId;
}
} // fn setLanguageId
/**
* Register a string in the translation table.
* @param string $p_key
* @param string $p_value
* @return void
*/
function registerString($p_key, $p_value)
{
if (substr($p_value, strlen($p_value)-3) == ":en"){
$p_value = substr($p_value, 0, strlen($p_value)-3);
}
$this->m_translationTable[$p_key] = $p_value;
} // fn registerString
/**
* Return the total number of strings in the translation table.
* @return int
*/
function getNumStrings()
{
return count($this->m_translationTable);
} // fn getNumStrings
/**
* Get the language code that is in the form <two_letter_language_code>_<english_name_of_language>.
*
* @return string
*/
function getLanguageId()
{
return $this->m_languageId;
} // fn getLanguageId
/**
* Get the two-letter language code for the translation table.
* @return string
*/
function getLanguageCode()
{
return $this->m_languageCode;
} // fn getLanguageCode
/**
* Get the two-letter country code.
* @return string
*/
function getCountryCode()
{
return $this->m_countryCode;
} // fn getCountryCode
/**
* Return the file path for the last file loaded.
* @return string
*/
function getSourceFile()
{
return $this->m_filePath;
} // fn getSourceFile
/**
* This is only for use by the LocalizerFileFormat functions.
* @access private
*/
function _setSourceFile($p_value)
{
$this->m_filePath = $p_value;
} // fn _setSourceFile
/**
* Return true if this LocalizerLanguage has the exact same
* translation strings as the given LocalizerLanguage.
*
* @param LocalizerLanguage $p_localizerLanguage
* @return boolean
*/
function equal($p_localizerLanguage)
{
if (count($this->m_translationTable) != count($p_localizerLanguage->m_translationTable)) {
return false;
}
foreach ($this->m_translationTable as $key => $value) {
if (!array_key_exists($key, $p_localizerLanguage->m_translationTable)) {
//echo "missing translation string: '$key'<br>";
return false;
}
if ($p_localizerLanguage->m_translationTable[$key] != $value) {
//echo "Non-matching values: '".$p_localizerLanguage->m_translationTable[$key]."' != '".$value."'<br>";
return false;
}
}
return true;
} // fn equal
/**
* Return a table indexed by the english language name, with the value being the
* target language equivalent.
*
* @return array
*/
function getTranslationTable()
{
return $this->m_translationTable;
}
/**
* Get the full path to the translation file.
*
* @param string $p_mode
* Either 'gs' or 'xml'.
* @return string
*/
function getFilePath($p_mode = null)
{
global $g_localizerConfig;
if (is_null($p_mode)) {
$p_mode = $this->m_mode;
}
if ($p_mode == 'xml') {
$relativePath = '/'.$this->m_languageId.'/'.$this->m_prefix.'.xml';
}
else {
$relativePath = '/'.$this->m_languageCode.'/'.$this->m_prefix.'.php';
}
return $g_localizerConfig['TRANSLATION_DIR'].$relativePath;
} // fn getFilePath
/**
* Return TRUE if the given string exists in the translation table.
*
* @param string $p_string
*
* @return boolean
*/
function keyExists($p_string)
{
return (isset($this->m_translationTable[$p_string]));
} // fn stringExists
/**
* Add a string to the translation table.
*
* @param string $p_key
* The english translation of the string.
*
* @param string $p_value
* Optional. If not specified, the value will be set to the same
* value as the key.
*
* @param int $p_position
* Optional. By default the string will be added to the end of the
* translation table.
*
* @return boolean
*/
function addString($p_key, $p_value = null, $p_position = null)
{
if (!is_null($p_position)
&& (!is_numeric($p_position) || ($p_position < 0)
|| ($p_position > count($this->m_translationTable)))) {
return false;
}
if (!is_string($p_key) || !is_string($p_value)) {
return false;
}
if (is_null($p_position)) {
// Position is not specified - add the string at the end
if (is_null($p_value)) {
$this->m_translationTable[$p_key] = $p_key;
}
else {
$this->m_translationTable[$p_key] = $p_value;
}
return true;
}
else {
// The position is specified
$begin = array_slice($this->m_translationTable, 0, $p_position);
$end = array_slice($this->m_translationTable, $p_position);
if (is_null($p_value)) {
$newStr = array($p_key => $p_key);
}
else {
$newStr = array($p_key => $p_value);
}
$this->m_translationTable = array_merge($begin, $newStr, $end);
return true;
}
} // fn addString
/**
* Get the position of a key or a value.
* @param string $p_key
* @param string $p_value
* @return mixed
* The position of the key/value in the array, FALSE if not found.
*/
function getPosition($p_key = null, $p_value = null)
{
$position = 0;
if (!is_null($p_key)) {
foreach ($this->m_translationTable as $key => $value) {
if ($p_key == $key) {
return $position;
}
$position++;
}
}
elseif (!is_null($p_value)) {
foreach ($this->m_translationTable as $value) {
if ($p_value == $value) {
return $position;
}
$position++;
}
}
return false;
} // fn getPosition
/**
* Get the string at the given position.
*
* @return array
* An array of two elements, the first is the key, the second is the value.
* They are indexed by 'key' and 'value'.
*/
function getStringAtPosition($p_position)
{
if (is_null($p_position) || !is_numeric($p_position) || ($p_position < 0)
|| ($p_position > count($this->m_translationTable))) {
return false;
}
$returnValue = array_splice($this->m_translationTable, $p_position, 0);
$keys = array_keys($returnValue);
$key = array_pop($keys);
$value = array_pop($returnValue);
return array('key' => $key, 'value' => $value);
} // fn getStringAtPosition
/**
* Change the key and optionally the value of the
* translation string. If the value isnt specified,
* it is not changed. If the key does not exist,
* it will be added. In this case, you can use p_position
* to specify where to add the string.
*
* @param string $p_oldKey
* @param string $p_newKey
* @param string $p_value
* @param int $p_position
* @return boolean
*/
function updateString($p_oldKey, $p_newKey, $p_value = null, $p_position = null)
{
if (!is_string($p_oldKey) || !is_string($p_newKey)) {
return false;
}
// Does the old string exist?
if (!isset($this->m_translationTable[$p_oldKey])) {
return $this->addString($p_newKey, $p_value, $p_position);
}
if ($p_oldKey == $p_newKey) {
// Just updating the value
if (!is_null($p_value) && ($p_value != $this->m_translationTable[$p_oldKey])) {
$this->m_translationTable[$p_oldKey] = $p_value;
return true;
}
// No changes
else {
return true;
}
}
// Updating the key (and possibly the value)
if (is_null($p_value)) {
$p_value = $this->m_translationTable[$p_oldKey];
}
$position = $this->getPosition($p_oldKey);
$success = $this->deleteString($p_oldKey);
$success &= $this->addString($p_newKey, $p_value, $position);
return $success;
} // fn updateString
/**
* Move a string to a different position in the translation array.
* This allows similiar strings to be grouped together.
*
* @param int $p_startPositionOrKey
* @param int $p_endPosition
*
* @return boolean
* TRUE on success, FALSE on failure.
*/
function moveString($p_startPositionOrKey, $p_endPosition)
{
// Check parameters
if (is_numeric($p_startPositionOrKey) && (($p_startPositionOrKey < 0)
|| ($p_startPositionOrKey > count($this->m_translationTable)))) {
return false;
}
if (!is_numeric($p_endPosition) || ($p_endPosition < 0)
|| ($p_endPosition > count($this->m_translationTable))) {
return false;
}
$startPosition = null;
if (is_numeric($p_startPositionOrKey)) {
$startPosition = $p_startPositionOrKey;
}
elseif (is_string($p_startPositionOrKey)) {
if (!isset($this->m_translationTable[$p_startPositionOrKey])) {
return false;
}
$startPosition = $this->getPosition($p_startPositionOrKey);
}
else {
return false;
}
// Success if we dont have to move the string anywhere
if ($startPosition == $p_endPosition) {
return true;
}
// Delete the string in the old position
$result = $this->deleteStringAtPosition($startPosition);
if (!$result) {
return false;
}
$key = $result['key'];
$value = $result['value'];
// Add the string in the new position
$result = $this->addString($key, $value, $p_endPosition);
if (!$result) {
return false;
}
return true;
} // fn moveString
/**
* Delete the string given by $p_key.
* @param string $p_key
* @return mixed
* The deleted string as array('key' => $key, 'value' => $value) on success,
* FALSE if it didnt exist.
*/
function deleteString($p_key)
{
if (isset($this->m_translationTable[$p_key])) {
$value = $this->m_translationTable[$p_key];
unset($this->m_translationTable[$p_key]);
return array('key'=>$p_key, 'value'=>$value);
}
return false;
} // fn deleteString
/**
* Delete a string at a specific position in the array.
* @param int $p_position
* @return mixed
* The deleted string as array($key, $value) on success, FALSE on failure.
*/
function deleteStringAtPosition($p_position)
{
if (!is_numeric($p_position) || ($p_position < 0)
|| ($p_position > count($this->m_translationTable))) {
return false;
}
$returnValue = array_splice($this->m_translationTable, $p_position, 1);
$keys = array_keys($returnValue);
$key = array_pop($keys);
$value = array_pop($returnValue);
return array('key' => $key, 'value' => $value);
} // fn deleteStringAtPosition
/**
* Synchronize the positions of the strings in the translation table
* with the positions of the string in the default language translation table.
*/
function fixPositions()
{
global $g_localizerConfig;
$defaultLanguage = new LocalizerLanguage($this->m_prefix,
$g_localizerConfig['DEFAULT_LANGUAGE']);
$defaultLanguage->loadFile(Localizer::GetMode());
$defaultTranslationTable = $defaultLanguage->getTranslationTable();
$count = 0;
$modified = false;
foreach ($defaultTranslationTable as $key => $value) {
if ($this->getPosition($key) != $count) {
$this->moveString($key, $count);
$modified = true;
}
$count++;
}
return $modified;
} // fn fixPositions
/**
* Sync with the default language file. This means
* adding any missing strings and fixing the positions of the strings to
* be the same as the default language file.
*/
function syncToDefault()
{
global $g_localizerConfig;
$defaultLanguage = new LocalizerLanguage($this->m_prefix,
$g_localizerConfig['DEFAULT_LANGUAGE']);
$defaultLanguage->loadFile(Localizer::GetMode());
$defaultTranslationTable = $defaultLanguage->getTranslationTable();
$count = 0;
$modified = false;
foreach ($defaultTranslationTable as $key => $value) {
if (!isset($this->m_translationTable[$key])) {
$this->addString($key, '', $count);
$modified = true;
}
$count++;
}
if ($g_localizerConfig['DELETE_UNUSED_ON_SYNC'] === true) {
foreach ($this->m_translationTable as $key => $value) {
if (!isset($defaultTranslationTable[$key])) {
$this->deleteString($key, '', $count);
$modified = true;
}
$count++;
}
}
return ($this->fixPositions() || $modified);
} // fn syncToDefault
/**
* Find the keys/values that match the given keyword.
*
* @param string $p_keyword
*
* @return array
*/
function search($p_keyword)
{
$matches = array();
foreach ($this->m_translationTable as $key => $value) {
if (empty($p_keyword) || stristr($key, $p_keyword) || stristr($value, $p_keyword)) {
$matches[$key] = $value;
}
}
return $matches;
} // fn search
/**
* Load a language file of the given type.
*
* @param string $p_type
* If not specified, it will use the current mode.
*
* @return boolean
*/
function loadFile($p_type = null)
{
if (is_null($p_type)) {
if (!empty($this->m_mode)) {
$p_type = $this->m_mode;
}
else {
$p_type = Localizer::GetMode();
if (is_null($p_type)) {
return false;
}
}
}
$className = 'LocalizerFileFormat_'.strtoupper($p_type);
if (class_exists($className)) {
$object = new $className();
if (method_exists($object, 'load')) {
return $object->load($this);
}
}
return false;
} // fn loadFile
/**
* Save the translation table as the given type.
*
* @param string $p_type
* If not specified, it will use the current mode.
*
* @return boolean
*/
function saveFile($p_type = null)
{
// Figure out the current mode.
if (is_null($p_type)) {
if (!empty($this->m_mode)) {
$p_type = $this->m_mode;
}
else {
$p_type = Localizer::GetMode();
if (is_null($p_type)) {
return false;
}
}
}
// Save in the requested mode.
$className = 'LocalizerFileFormat_'.strtoupper($p_type);
if (class_exists($className)) {
$object = new $className();
if (method_exists($object, 'save')) {
return $object->save($this);
}
}
return false;
} // fn saveFile
/**
* Erase all the values in the translation table, but
* keep the keys.
* @return void
*/
function clearValues()
{
foreach ($this->m_translationTable as $key => $value) {
$this->m_translationTable[$key] = '';
}
} // fn clearValues
/**
* For debugging purposes, displays the the translation table
* in an HTML table.
*/
function dumpToHtml()
{
echo "<pre>";
if (!empty($this->m_filePath)) {
echo "<b>File: ".$this->m_filePath."</b><br>";
}
echo "<b>Language Code: ".$this->m_languageId."</b><br>";
echo "<table>";
foreach ($this->m_translationTable as $key => $value) {
echo "<tr><td>'$key'</td><td>'$value'</td></tr>";
}
echo "</table>";
echo "</pre>";
} // fn dumpToHtml
} // class LocalizerLanguage
?>