PageRenderTime 69ms CodeModel.GetById 19ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 1ms

/campsite/src/admin-files/localizer/LocalizerLanguage.php

https://github.com/joechrysler/Campsite
PHP | 694 lines | 391 code | 68 blank | 235 comment | 92 complexity | 7844b0407e49a1285ec5bbf3d8cf6670 MD5 | raw file
  1<?PHP
  2/**
  3 * @package Campware
  4 */
  5
  6/**
  7 * Includes
  8 */
  9require_once('PEAR.php');
 10require_once('LocalizerConfig.php');
 11require_once('LocalizerFileFormat.php');
 12require_once($GLOBALS['g_campsiteDir'].'/db_connect.php');
 13
 14/**
 15 * @package Campware
 16 */
 17class LocalizerLanguage {
 18	var $m_translationTable = array();
 19	var $m_languageCode = '';
 20	var $m_countryCode = '';
 21	var $m_languageId = '';
 22	var $m_mode = '';
 23	var $m_prefix = '';
 24	var $m_filePath = '';
 25
 26	/**
 27	 * A LocalizerLanguage is basically a translation table.
 28	 *
 29	 * You can use this class to manipulate the translation table:
 30	 * such as add, delete, and move strings.
 31	 *
 32	 * @param string $p_prefix
 33	 *		The beginning of the file name, up to the first dot ('.').
 34	 *
 35	 * @param string $p_directory
 36	 *		The location of the language file, relative to LOCALIZER_BASE_DIR.
 37	 *
 38	 * @param string $p_languageId
 39	 *		The language ID for this language, which can be in one of two forms:
 40	 *      1) The two-letter language code (e.g. "en").
 41	 *      2) The two-letter language code, underscore, two-letter country code
 42	 *         (e.g. "en_US")
 43	 */
 44	function LocalizerLanguage($p_prefix, $p_languageId = null)
 45	{
 46		if (!is_null($p_languageId)) {
 47			$this->setLanguageId($p_languageId);
 48		}
 49		$this->m_prefix = $p_prefix;
 50	} // constructor
 51
 52
 53	/**
 54	 * Return the filename prefix.
 55	 * @return string
 56	 */
 57	function getPrefix()
 58	{
 59	    return $this->m_prefix;
 60	} // fn getPrefix
 61
 62
 63	/**
 64	 * This will return 'gs' or 'xml'
 65	 * @return string
 66	 */
 67	function getMode()
 68	{
 69		return $this->m_mode;
 70	} // fn getMode
 71
 72
 73	/**
 74	 * Set the mode to be 'xml' or 'gs'.
 75	 * @param string $p_value
 76	 * @return void
 77	 */
 78	function setMode($p_value)
 79	{
 80		$p_value = strtolower($p_value);
 81		if (($p_value == 'xml') || ($p_value == 'gs')) {
 82			$this->m_mode = $p_value;
 83		}
 84	} // fn setMode
 85
 86
 87	/**
 88	 * Set the language code - this can take either the two-letter language code
 89	 * or the LL_CC extended version , where LL is the language code and CC
 90	 * is the country code.
 91	 *
 92	 * @param string $p_languageId
 93	 * @return void
 94	 */
 95	function setLanguageId($p_languageId)
 96	{
 97		if (strlen($p_languageId) > 2) {
 98			$this->m_languageCode = substr($p_languageId, 0, 2);
 99			$this->m_countryCode = substr($p_languageId, 3, 2);
100			$this->m_languageId = $p_languageId;
101		}
102		else {
103			$this->m_languageCode = $p_languageId;
104			$this->m_languageId = $p_languageId;
105		}
106	} // fn setLanguageId
107
108
109    /**
110     * Register a string in the translation table.
111     * @param string $p_key
112     * @param string $p_value
113     * @return void
114     */
115    function registerString($p_key, $p_value)
116    {
117        if (substr($p_value, strlen($p_value)-3) == ":en"){
118            $p_value = substr($p_value, 0, strlen($p_value)-3);
119        }
120        $this->m_translationTable[$p_key] = $p_value;
121    } // fn registerString
122
123
124    /**
125     * Return the total number of strings in the translation table.
126     * @return int
127     */
128    function getNumStrings()
129    {
130    	return count($this->m_translationTable);
131    } // fn getNumStrings
132
133
134    /**
135     * Get the language code that is in the form <two_letter_language_code>_<english_name_of_language>.
136     *
137     * @return string
138     */
139	function getLanguageId()
140	{
141		return $this->m_languageId;
142	} // fn getLanguageId
143
144
145	/**
146	 * Get the two-letter language code for the translation table.
147	 * @return string
148	 */
149	function getLanguageCode()
150	{
151		return $this->m_languageCode;
152	} // fn getLanguageCode
153
154
155	/**
156	 * Get the two-letter country code.
157	 * @return string
158	 */
159	function getCountryCode()
160	{
161	    return $this->m_countryCode;
162	} // fn getCountryCode
163
164
165	/**
166	 * Return the file path for the last file loaded.
167	 * @return string
168	 */
169	function getSourceFile()
170	{
171		return $this->m_filePath;
172	} // fn getSourceFile
173
174
175	/**
176	 * This is only for use by the LocalizerFileFormat functions.
177	 * @access private
178	 */
179	function _setSourceFile($p_value)
180	{
181	    $this->m_filePath = $p_value;
182	} // fn _setSourceFile
183
184
185	/**
186	 * Return true if this LocalizerLanguage has the exact same
187	 * translation strings as the given LocalizerLanguage.
188	 *
189	 * @param LocalizerLanguage $p_localizerLanguage
190	 * @return boolean
191	 */
192	function equal($p_localizerLanguage)
193	{
194		if (count($this->m_translationTable) != count($p_localizerLanguage->m_translationTable)) {
195			return false;
196		}
197		foreach ($this->m_translationTable as $key => $value) {
198			if (!array_key_exists($key, $p_localizerLanguage->m_translationTable)) {
199				//echo "missing translation string: '$key'<br>";
200				return false;
201			}
202			if ($p_localizerLanguage->m_translationTable[$key] != $value) {
203				//echo "Non-matching values: '".$p_localizerLanguage->m_translationTable[$key]."' != '".$value."'<br>";
204				return false;
205			}
206		}
207		return true;
208	} // fn equal
209
210
211	/**
212	 * Return a table indexed by the english language name, with the value being the
213	 * target language equivalent.
214	 *
215	 * @return array
216	 */
217	function getTranslationTable()
218	{
219		return $this->m_translationTable;
220	}
221
222
223	/**
224	 * Return the value for the given key.
225	 *
226	 * @param unknown_type $p_key
227	 */
228	function getValue($p_key)
229	{
230		if (isset($this->m_translationTable[$p_key])) {
231			return $this->m_translationTable[$p_key];
232		} else {
233			return null;
234		}
235	} // fn getValue
236
237
238	/**
239	 * Get the full path to the translation file.
240	 *
241	 * @param string $p_mode
242	 *		Either 'gs' or 'xml'.
243     * @return string
244     */
245    function getFilePath($p_mode = null)
246    {
247        global $g_localizerConfig;
248    	if (is_null($p_mode)) {
249    		$p_mode = $this->m_mode;
250    	}
251    	if ($p_mode == 'xml') {
252        	$relativePath = '/'.$this->m_languageId.'/'.$this->m_prefix.'.xml';
253    	}
254    	else {
255    		$relativePath = '/'.$this->m_languageCode.'/'.$this->m_prefix.'.php';
256    	}
257    	return $g_localizerConfig['TRANSLATION_DIR'].$relativePath;
258    } // fn getFilePath
259
260
261    /**
262     * Return TRUE if the given string exists in the translation table.
263     *
264     * @param string $p_string
265     *
266     * @return boolean
267     */
268    function keyExists($p_string)
269    {
270    	return (isset($this->m_translationTable[$p_string]));
271    } // fn stringExists
272
273
274    /**
275     * Add a string to the translation table.
276     *
277     * @param string $p_key
278     *		The english translation of the string.
279     *
280     * @param string $p_value
281     *		Optional.  If not specified, the value will be set to the same
282     *		value as the key.
283     *
284     * @param int $p_position
285     *		Optional.  By default the string will be added to the end of the
286     *		translation table.
287     *
288     * @return boolean
289     */
290    function addString($p_key, $p_value = null, $p_position = null)
291    {
292    	if (!is_null($p_position)
293    		&& (!is_numeric($p_position) || ($p_position < 0)
294    			|| ($p_position > count($this->m_translationTable)))) {
295    		return false;
296    	}
297    	if (!is_string($p_key) || !is_string($p_value)) {
298    		return false;
299    	}
300    	if (is_null($p_position)) {
301    		// Position is not specified - add the string at the end
302    		if (is_null($p_value)) {
303    			$this->m_translationTable[$p_key] = $p_key;
304    		}
305    		else {
306    			$this->m_translationTable[$p_key] = $p_value;
307    		}
308    		return true;
309    	}
310		else {
311			// The position is specified
312			$begin = array_slice($this->m_translationTable, 0, $p_position);
313			$end = array_slice($this->m_translationTable, $p_position);
314			if (is_null($p_value)) {
315				$newStr = array($p_key => $p_key);
316			}
317			else {
318				$newStr = array($p_key => $p_value);
319			}
320			$this->m_translationTable = array_merge($begin, $newStr, $end);
321			return true;
322		}
323    } // fn addString
324
325
326    /**
327     * Get the position of a key or a value.
328     * @param string $p_key
329     * @param string $p_value
330     * @return mixed
331     *		The position of the key/value in the array, FALSE if not found.
332     */
333    function getPosition($p_key = null, $p_value = null)
334    {
335    	$position = 0;
336    	if (!is_null($p_key)) {
337	    	foreach ($this->m_translationTable as $key => $value) {
338	    		if ($p_key == $key) {
339	    			return $position;
340	    		}
341	    		$position++;
342	    	}
343    	}
344    	elseif (!is_null($p_value)) {
345	    	foreach ($this->m_translationTable as $value) {
346	    		if ($p_value == $value) {
347	    			return $position;
348	    		}
349	    		$position++;
350	    	}
351    	}
352    	return false;
353    } // fn getPosition
354
355
356    /**
357     * Get the string at the given position.
358     *
359     * @return array
360     * 		An array of two elements, the first is the key, the second is the value.
361     *		They are indexed by 'key' and 'value'.
362     */
363    function getStringAtPosition($p_position)
364    {
365    	if (is_null($p_position) || !is_numeric($p_position) || ($p_position < 0)
366    			|| ($p_position > count($this->m_translationTable))) {
367    		return false;
368    	}
369    	$returnValue = array_splice($this->m_translationTable, $p_position, 0);
370    	$keys = array_keys($returnValue);
371    	$key = array_pop($keys);
372    	$value = array_pop($returnValue);
373    	return array('key' => $key, 'value' => $value);
374    } // fn getStringAtPosition
375
376
377    /**
378     * Change the key and optionally the value of the
379     * translation string.  If the value isnt specified,
380     * it is not changed.  If the key does not exist,
381     * it will be added.  In this case, you can use p_position
382     * to specify where to add the string.
383     *
384     * @param string $p_oldKey
385     * @param string $p_newKey
386     * @param string $p_value
387     * @param int $p_position
388     * @return boolean
389     */
390    function updateString($p_oldKey, $p_newKey, $p_value = null, $p_position = null)
391    {
392    	if (!is_string($p_oldKey) || !is_string($p_newKey)) {
393    		return false;
394    	}
395    	// Does the old string exist?
396    	if (!isset($this->m_translationTable[$p_oldKey])) {
397    		return $this->addString($p_newKey, $p_value, $p_position);
398    	}
399    	if ($p_oldKey == $p_newKey) {
400	    	// Just updating the value
401    		if (!is_null($p_value) && ($p_value != $this->m_translationTable[$p_oldKey])) {
402    			$this->m_translationTable[$p_oldKey] = $p_value;
403    			return true;
404    		}
405    		// No changes
406    		else {
407    			return true;
408    		}
409    	}
410
411    	// Updating the key (and possibly the value)
412    	if (is_null($p_value)) {
413    		$p_value = $this->m_translationTable[$p_oldKey];
414    	}
415    	$position = $this->getPosition($p_oldKey);
416    	$success = $this->deleteString($p_oldKey);
417    	$success &= $this->addString($p_newKey, $p_value, $position);
418    	return $success;
419    } // fn updateString
420
421
422    /**
423     * Move a string to a different position in the translation array.
424     * This allows similiar strings to be grouped together.
425     *
426     * @param int $p_startPositionOrKey
427     * @param int $p_endPosition
428     *
429     * @return boolean
430     *		TRUE on success, FALSE on failure.
431     */
432    function moveString($p_startPositionOrKey, $p_endPosition)
433    {
434    	// Check parameters
435    	if (is_numeric($p_startPositionOrKey) && (($p_startPositionOrKey < 0)
436    		|| ($p_startPositionOrKey > count($this->m_translationTable)))) {
437    		return false;
438    	}
439    	if (!is_numeric($p_endPosition) || ($p_endPosition < 0)
440    		|| ($p_endPosition > count($this->m_translationTable))) {
441    		return false;
442    	}
443    	$startPosition = null;
444    	if (is_numeric($p_startPositionOrKey)) {
445			$startPosition = $p_startPositionOrKey;
446    	}
447    	elseif (is_string($p_startPositionOrKey)) {
448    		if (!isset($this->m_translationTable[$p_startPositionOrKey])) {
449    			return false;
450    		}
451    		$startPosition = $this->getPosition($p_startPositionOrKey);
452    	}
453    	else {
454    		return false;
455    	}
456
457    	// Success if we dont have to move the string anywhere
458		if ($startPosition == $p_endPosition) {
459			return true;
460		}
461    	// Delete the string in the old position
462    	$result = $this->deleteStringAtPosition($startPosition);
463    	if (!$result) {
464    		return false;
465    	}
466    	$key = $result['key'];
467    	$value = $result['value'];
468
469    	// Add the string in the new position
470    	$result = $this->addString($key, $value, $p_endPosition);
471    	if (!$result) {
472    		return false;
473    	}
474    	return true;
475    } // fn moveString
476
477
478    /**
479     * Delete the string given by $p_key.
480     * @param string $p_key
481     * @return mixed
482     *		The deleted string as array('key' => $key, 'value' => $value) on success,
483     *		FALSE if it didnt exist.
484     */
485    function deleteString($p_key)
486    {
487    	if (isset($this->m_translationTable[$p_key])) {
488    		$value = $this->m_translationTable[$p_key];
489    		unset($this->m_translationTable[$p_key]);
490    		return array('key'=>$p_key, 'value'=>$value);
491    	}
492    	return false;
493    } // fn deleteString
494
495
496    /**
497     * Delete a string at a specific position in the array.
498     * @param int $p_position
499     * @return mixed
500     *		The deleted string as array($key, $value) on success, FALSE on failure.
501     */
502    function deleteStringAtPosition($p_position)
503    {
504    	if (!is_numeric($p_position) || ($p_position < 0)
505    		|| ($p_position > count($this->m_translationTable))) {
506    		return false;
507    	}
508    	$returnValue = array_splice($this->m_translationTable, $p_position, 1);
509    	$keys = array_keys($returnValue);
510    	$key = array_pop($keys);
511    	$value = array_pop($returnValue);
512    	return array('key' => $key, 'value' => $value);
513    } // fn deleteStringAtPosition
514
515
516    /**
517     * Synchronize the positions of the strings in the translation table
518     * with the positions of the string in the default language translation table.
519     */
520    function fixPositions()
521    {
522        global $g_localizerConfig;
523        $defaultLanguage = new LocalizerLanguage($this->m_prefix,
524                                                 $g_localizerConfig['DEFAULT_LANGUAGE']);
525        $defaultLanguage->loadFile(Localizer::GetMode());
526        $defaultTranslationTable = $defaultLanguage->getTranslationTable();
527    	$count = 0;
528    	$modified = false;
529    	foreach ($defaultTranslationTable as $key => $value) {
530    		if ($this->getPosition($key) != $count) {
531    			$this->moveString($key, $count);
532    			$modified = true;
533    		}
534    		$count++;
535    	}
536    	return $modified;
537    } // fn fixPositions
538
539
540    /**
541     * Sync with the default language file.  This means
542     * adding any missing strings and fixing the positions of the strings to
543     * be the same as the default language file.
544     */
545    function syncToDefault()
546    {
547        global $g_localizerConfig;
548        $defaultLanguage = new LocalizerLanguage($this->m_prefix,
549                                                  $g_localizerConfig['DEFAULT_LANGUAGE']);
550        $defaultLanguage->loadFile(Localizer::GetMode());
551        $defaultTranslationTable = $defaultLanguage->getTranslationTable();
552    	$count = 0;
553    	$modified = false;
554    	foreach ($defaultTranslationTable as $key => $value) {
555    		if (!isset($this->m_translationTable[$key])) {
556    			$this->addString($key, '', $count);
557    			$modified = true;
558    		}
559    		$count++;
560    	}
561    	return ($this->fixPositions() || $modified);
562    } // fn syncToDefault
563
564
565    /**
566     * Find the keys/values that match the given keyword.
567     *
568     * @param string $p_keyword
569     *
570     * @return array
571     */
572    function search($p_keyword)
573    {
574    	$matches = array();
575    	foreach ($this->m_translationTable as $key => $value) {
576    		if (empty($p_keyword) || stristr($key, $p_keyword) || stristr($value, $p_keyword)) {
577    			$matches[$key] = $value;
578    		}
579    	}
580    	return $matches;
581    } // fn search
582
583
584    /**
585     * Load a language file of the given type.
586     *
587     * @param string $p_type
588     *		If not specified, it will use the current mode.
589     *
590     * @return mixed
591     * 		Return TRUE on success, PEAR_Error on failure.
592     */
593    function loadFile($p_type = null)
594    {
595        if (is_null($p_type)) {
596            if (!empty($this->m_mode)) {
597                $p_type = $this->m_mode;
598            }
599            else {
600        		$p_type = Localizer::GetMode();
601        		if (is_null($p_type)) {
602        		    return false;
603        		}
604            }
605        }
606        $className = 'LocalizerFileFormat_'.strtoupper($p_type);
607        if (class_exists($className)) {
608            $object = new $className();
609            if (method_exists($object, 'load')) {
610                $result = $object->load($this);
611                return $result;
612            } else {
613	        	return new PEAR_Error("LocalizerLanguage::loadFile(): Class $className is missing the 'load' function.");
614            }
615        } else {
616        	return new PEAR_Error("LocalizerLanguage::loadFile(): Class $className does not exist.");
617        }
618    } // fn loadFile
619
620
621    /**
622     * Save the translation table as the given type.
623     *
624     * @param string $p_type
625     *		If not specified, it will use the current mode.
626     *
627     * @return mixed
628     * 		true
629     * 		PEAR_Error
630     */
631    function saveFile($p_type = null)
632    {
633        // Figure out the current mode.
634        if (is_null($p_type)) {
635            if (!empty($this->m_mode)) {
636                $p_type = $this->m_mode;
637            }
638            else {
639        		$p_type = Localizer::GetMode();
640        		if (is_null($p_type)) {
641        		    return new PEAR_Error("Localizer: unknown mode");
642        		}
643            }
644        }
645        // Save in the requested mode.
646        $className = 'LocalizerFileFormat_'.strtoupper($p_type);
647        if (class_exists($className)) {
648            $object = new $className();
649            if (method_exists($object, 'save')) {
650                return $object->save($this);
651            } else {
652            	return new PEAR_Error("Class $className does not have a 'save' function");
653            }
654        } else {
655    		return new PEAR_Error("Class $className does not exist.");
656        }
657    } // fn saveFile
658
659
660    /**
661     * Erase all the values in the translation table, but
662     * keep the keys.
663     * @return void
664     */
665    function clearValues()
666    {
667    	foreach ($this->m_translationTable as $key => $value) {
668    		$this->m_translationTable[$key] = '';
669    	}
670    } // fn clearValues
671
672
673    /**
674     * For debugging purposes, displays the the translation table
675     * in an HTML table.
676     */
677    function dumpToHtml()
678    {
679    	echo "<pre>";
680    	if (!empty($this->m_filePath)) {
681    		echo "<b>File: ".$this->m_filePath."</b><br>";
682    	}
683    	echo "<b>Language Code: ".$this->m_languageId."</b><br>";
684    	echo "<table>";
685    	foreach ($this->m_translationTable as $key => $value) {
686    		echo "<tr><td>'$key'</td><td>'$value'</td></tr>";
687    	}
688    	echo "</table>";
689    	echo "</pre>";
690    } // fn dumpToHtml
691
692} // class LocalizerLanguage
693
694?>