Apache Zeta Components Manual :: File Source for ts_backend.php
Source for file ts_backend.php
Documentation is available at ts_backend.php
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version //autogentag//
* Translation backend that reads Qt's Linguist TS files.
* This class is the backend that can read Qt's Linguist files as source for a
* translation. The format is an XML file, which contains contexts and all the
* $a = new ezcTranslationTsBackend(
* array ( 'format' => '[LOCALE].xml' )
* $b = new ezcTranslationManager( $a );
* The reader capabilities of this class (the implementation of
* ezcTranslationContextRead) can be used it two different ways, where the
* second one is the more elegant approach.
* $backend = new ezcTranslationTsBackend( "files/translations" );
* $backend->options->format = '[LOCALE].xml';
* $backend->initReader( 'nb-no' );
* while ( $backend->valid() )
* $contextName = $backend->key();
* $contextData = $backend->current();
* // do something with the data
* $backend = new ezcTranslationTsBackend( "{$currentDir}/files/translations" );
* $backend->options->format = '[LOCALE].xml';
* $backend->initReader( 'nb-no' );
* foreach ( $backend as $contextName => $contextData )
* // do something with the data
* For a more extensive example see {@link ezcTranslationManager}.
* @property ezcTranslationTsBackendOptions $options
* Contains the options for this class.
* @version //autogentag//
class ezcTranslationTsBackend implements ezcTranslationBackend, ezcTranslationContextRead, ezcTranslationContextWrite
* The last read context, as read by next() method.
* The next() method is a part of the {@link ezcTranslationContextRead}
* interface. The first element is the name, the second an array with
* {@link ezcTranslationData} objects. An example of such an array is:
* 'design/admin/class/classlist',
* new ezcTranslationData( 'Edit', 'Rediger', false, ezcTranslationData::TRANSLATED ),
* new ezcTranslationData( 'Create a copy of the <%class_name> class.', 'Lag en kopi av klassen <%class_name>.', false, ezcTranslationData::TRANSLATED ),
private $currentContext =
null;
* Handle for the XML parser used as part of the ezcTranslationContextRead interface.
private $xmlParser =
null;
* Contains the DOM tree for modifications while writing a new translation file
* Contains the locale used for writing a new translation file
private $writeLocale =
null;
* Container to hold the properties
* @var array(string=>mixed)
* Constructs a new ezcTranslationTsBackend that will use the file specified by $location.
* You can specify additional options through the $options parameter. See
* the documentation for the {@link ezcTranslationTsBackend::setOptions()}
* method for supported options.
* @throws ezcTranslationNotConfiguredException if $location is not set or is empty.
* @param string $location
* @param array(string=>mixed) $options
function __construct( $location, array $options =
array() )
if ( !$location ||
!strlen( $location ) )
$this->properties['options']->location =
$location;
* This method allows you to change the options of the translation backend.
* @param ezcTranslationTsBackendOptions $options The options to set.
* @throws ezcBaseSettingNotFoundException
* If you tried to set a non-existent option value.
* @throws ezcBaseSettingValueException
* If the value is not valid for the desired option.
* @throws ezcBaseValueException
* If you submit neither an array nor an instance of
* ezcTranslationTsBackendOptions.
$this->options->merge( $options );
$this->options =
$options;
* Returns the current options.
* Returns the options currently set for this backend.
* @return ezcTranslationTsBackendOptions The current options.
* Returns the filename for the translation file using the locale $locale.
* This function uses the <i>location</i> and <i>format</i> options,
* combined with the $locale parameter to form a filename that contains the
* translation belonging to the specified locale.
$filename =
$this->options->location .
$this->options->format;
$filename =
str_replace( '[LOCALE]', $locale, $filename );
* Creates an SimpleXML parser object for the locale $locale.
* You can set the class of the returned object through the $returnClass
* parameter. That class should extend the SimpleXMLElement class.
* This function checks if the <i>location</i> setting is made, if the file
* with the filename as returned by buildTranslationFileName() exists and
* creates a SimpleXML parser object for this file. If either the setting
* is not made, or the file doesn't exists it throws an exception.
* @throws ezcTranslationMissingTranslationFileException if the translation
* @param string $returnClass The class of the returned XML Parser Object.
* @return object The created parser. The parameter $returnClass
* determines what type of class gets returned. The
* classname that you specify should be inherited from
* Creates a DOM parser object for the locale $locale.
* This function checks if the <i>location</i> setting is made, if the file
* with the filename as returned by buildTranslationFileName() exists and
* creates a DOM parser object for this file. If the setting
* is not made, it throws an exception. IF the file does not exist, a new
* DomDocument is created.
* @return object The created parser.
$dom =
new DOMDocument( '1.0', 'UTF-8' );
$dom->formatOutput =
true;
$root =
$dom->createElement( 'TS' );
$dom->appendChild( $root );
$dom =
new DOMDocument( '1.0', 'UTF-8' );
$dom->preserveWhiteSpace =
false;
$dom->formatOutput =
true;
$root =
$dom->getElementsByTagName( 'TS' )->item( 0 );
* Returns the data from the XML element $message as an
* ezcTranslationData object.
* @param SimpleXMLElement $message
* @return ezcTranslationData
private function parseSimpleXMLMessage( SimpleXMLElement $message )
if ( $message->translation['type'] ==
'unfinished' )
else if ( $message->translation['type'] ==
'obsolete' )
if ( $this->options->keepObsolete )
$source =
trim( (string)
$message->source );
$translation =
trim( (string)
$message->translation );
$comment =
trim( (string)
$message->comment );
$source =
strlen( $source ) ?
$source :
false;
$translation =
strlen( $translation ) ?
$translation :
false;
$comment =
strlen( $comment ) ?
$comment :
false;
$location =
$message->location;
$file =
trim( (string)
$location['filename'] );
$line =
trim( (string)
$location['line'] );
* Returns a array containing a translation map for the locale $locale
* and the context $context.
* This method returns an array containing the translation map for the
* specified $locale and $context. It uses the location and
* format options to locate the file, unless caching is
* @throws ezcTranslationContextNotAvailableException if a context is not
* @throws ezcTranslationMissingTranslationFileException if the translation
* @throws ezcTranslationNotConfiguredException if the option <i>format</i>
* is not set before this method is called.
* @return array(ezcTranslationData)
$contextElements =
array();
foreach ( $ts as $trContext )
if ( (string)
$trContext->name ==
$context )
foreach ( $trContext as $message )
if ( $message->source !=
'' )
$element =
$this->parseSimpleXMLMessage( $message );
$contextElements[] =
$element;
* Returns a list with all context names for the locale $locale.
* @throws ezcTranslationMissingTranslationFileException if the translation
* @throws ezcTranslationNotConfiguredException if the option <i>format</i>
* is not set before this method is called.
foreach ( $ts as $trContext )
$contextNames[] = (string)
$trContext->name;
* Initializes the reader to read from locale $locale.
* Opens the translation file.
* @throws ezcTranslationNotConfiguredException if the option <i>format</i>
* is not set before this method is called.
$this->xmlParser->rewind();
* Deinitializes the reader
* This method should be called after the haveMore() method returns false
* @throws ezcTranslationException when the reader is not initialized with
* This method stores the context that it received to the backend specified
* @throws ezcTranslationWriterNotInitializedException when the writer is
* not initialized with initWriter().
* @param string $context The context's name
* @param array(ezcTranslationData) $data The context's translation map
if ( is_null( $this->dom ) )
$root =
$dom->getElementsByTagName( 'TS' )->item( 0 );
// find the context element
$xpath =
new DOMXPath( $dom );
$result =
$xpath->query( '//context/name[text()="' .
htmlspecialchars( $context ) .
'"]' );
// If the context does not exist, we create a node for it; otherwise we just use it.
$contextNode =
$dom->createElement( 'context' );
$nameNode =
$dom->createElement( 'name', htmlspecialchars( $context ) );
$contextNode->appendChild( $nameNode );
$root->appendChild( $contextNode );
$contextNode =
$result->item( 0 )->parentNode;
// for every entry, we add a new message
foreach ( $data as $info )
// check if the string is already there, if so, remove it first
$xpath =
new DOMXPath( $dom );
$xpathString =
str_replace( '"', '",\'"\',"', $info->original );
$result =
$xpath->query( 'message/source[text()=concat("' .
$xpathString .
'","")]', $contextNode );
$node =
$result->item( 0 )->parentNode;
$contextNode->removeChild( $node );
// create the new element
$message =
$dom->createElement( 'message' );
$message->appendChild( $source );
$translation =
$dom->createElement( 'translation', htmlspecialchars( $info->translation ) );
$translation->setAttribute( 'type', 'unfinished' );
$translation->setAttribute( 'type', 'obsolete' );
$message->appendChild( $translation );
$comment =
$dom->createElement( 'comment', htmlspecialchars( $info->comment ) );
$message->appendChild( $comment );
if ( $info->filename &&
$info->line )
$location =
$dom->createElement( 'location' );
$location->setAttribute( 'filename', $info->filename );
$location->setAttribute( 'line', $info->line );
$message->appendChild( $location );
$contextNode->appendChild( $message );
* Initializes the writer to write to locale $locale.
* Opens the translation file.
* @throws ezcTranslationNotConfiguredException if the option <i>format</i>
* is not set before this method is called.
$this->writeLocale =
$locale;
* Deinitializes the writer
$this->dom->save( $filename );
* Advanced to the next context.
* This method parses a little bit more of the XML file to be able to
* return the next context. If no more contexts are available it sets the
* $currentContext member variable to null, so that the valid() method can
* pick this up. If there are more contexts available it reads the context
* from the file and stores it into the $currentContext member variable.
* This method is used for iteration as part of the Iterator interface.
* @throws ezcTranslationReaderNotInitializedException when the reader is
* not initialized with initReader().
$valid =
$this->xmlParser->valid();
$newContext =
array( trim( $this->xmlParser->getChildren()->name), array() );
foreach ( $this->xmlParser->getChildren()->message as $data )
$translationItem =
$this->parseSimpleXMLMessage( $data );
if ( !is_null( $translationItem ) )
$newContext[1][] =
$translationItem;
$this->xmlParser->next();
* Returns whether there is a new context available.
* This method checks whether a valid context was read. It checks the
* $currentContext member variable for the status.
* This method is used for iteration as part of the Iterator interface.
* @throws ezcTranslationReaderNotInitializedException when the reader is
* not initialized with initReader().
* Returns the current context
* This method returns the latest read context, that the haveMore() method
* put into the $currentContext property. See
* {@link ezcTranslationTsBackend::$currentContext} for the format of this
* This method is used for iteration as part of the Iterator interface.
* @throws ezcTranslationReaderNotInitializedException when the reader is
* not initialized with initReader().
* @return array The current context's translation map
* Returns the current context's data.
* This method returns the latest read context, that the next() method
* put into the $currentContext property. See
* {@link ezcTranslationTsBackend::$currentContext} for the format of this
* This method is used for iteration as part of the Iterator interface.
* @throws ezcTranslationReaderNotInitializedException when the reader is
* not initialized with initReader().
* @return array The current context's translation map
* Returns the current context's name.
* This method returns the latest read context, that the next() method
* put into the $currentContext property. See
* {@link ezcTranslationTsBackend::$currentContext} for the format of this
* This method is used for iteration as part of the Iterator interface.
* @throws ezcTranslationReaderNotInitializedException when the reader is
* not initialized with initReader().
* @return string The current context's name
* Empty function to satisfy the Iterator interface.
* The iterator interface expects this method to rewind to the start of
* the array. As we do not support rewinding actually, the only thing that
* the rewind() implementation does is reading the first element from the
* translation file. There are no side effects either if you just use the
* foreach or while methods. (See class introduction for an example).
* This method is used for iteration as part of the Iterator interface.
* @throws ezcTranslationReaderNotInitializedException when the reader is
* not initialized with initReader().
* @throws ezcBasePropertyNotFoundException
* If the the desired property is not found.
* @param string $propertyName Name of the property.
* @return mixed Value of the property or null.
public function __get( $propertyName )
* @throws ezcBaseValueException
* If a the value for the property options is not an instance of
* ezcTranslationTsBackendOptions.
* @throws ezcBasePropertyNotFoundException
* If the the desired property is not found.
* @param string $propertyName Name of the property.
* @param mixed $val The value for the property.
public function __set( $propertyName, $val )
* @param string $propertyName Name of the property.
* @return bool True is the property is set, otherwise false.
public function __isset( $propertyName )