Hi,
I started yesterday with a ezlupdate.php script. I attached what I came
up with until today. Replace "require_once 'init.php';" with your
ezcComponents Setup.
The script reads all templates in a directory and extracts the language
strings. I used the existing functionality of the translation component
for manipulating translation files. Therefore it's not possible to
delete strings. Maybe there should be a new status "DELETED" that makes
storeContext() delete the string from the file.
I mark obsolete strings but only if the filename properties match.
This is not perfect as the filename is an absolute path at the moment
and not relative to the template dir. I'd recommend to change this.
For normal strings this works fine. But if you use HTML or double
quotes, you run into the following problems:
a) xpath for finding messages in 'ts_backend.php', line 436
The xpath query for finding the messages is not working properly if
there are the same strings in different contexts.
Fix: don't use '//' in the xpath query which forces the search to start
at the root element and not within the given context
$result = $xpath->query( 'message/source[text()="' . htmlspecialchars(
$info->original ) . '"]', $contextNode );
b) the same xpath doesn't work if there is HTML in the string
Within the DOM tree all reserved characters seem to be decoded.
Result: The xpath search for the encoded string fails. Therefore there
shouldn't be a htmlspecialchars() call for building the query.
$result = $xpath->query( 'message/source[text()="' . $info->original .
'"]', $contextNode );
HTML is working then.
c) double quotes in translation strings
This doesn't work: {tr "This is the \"root\" element!"}
First problem: String extractor doesn't strip slashes.
stripslashes() needs to be added to visitTranslationTstNode in
ezcTemplateTranslationStringExtracter.
Second problem: All quotes are decoded in the xpath query call (see b))
and therefore it's impossible to have both quote types in one string.
All xpath queries containing double quotes fail.
The only solution I found is to use concat(). The xpath needs to be
changed again:
$result = $xpath->query( 'message/source[text()=concat("'.str_replace(
'"', '",\'"\',"', $info->original ).'","")]', $contextNode );
The concat() function needs at least two parameters. In order to meet
this requirement there is an empty string at the end of every concat() call.
I hope this is what you were looking for.
Regards,
Andi
Derick Rethans schrieb:
On Wed, 2 Apr 2008, Andreas Schamberger wrote:
I've got a question regarding the new TemplateTranslationTiein:
For ezPublish templates there is the ezlupdate program. What are the
plans for ezcTemplate? Update of ezlupdate or plain PHP solution?
There is some code that extracts the translations from templates
already, but it has not been converted into a full blown script yet. For
the eZ Publish version that will use the new template and translation
components there will most likely be a PHP-only solution as replacement
for ezlupdate.
What's the schedule for this missing part of the TemplateTranslationTiein?
We hope to get it done before the release, but there are some slightly
more importent things to be done first. If you are interested in helping
out a bit, that would be most welcome. I attached a script that shows
how to extract strings from a template.
Another thing I would recommend to add to the TemplateTranslationTiein
is a developer mode for the TemplateTranslationTieIn. I'd like to see a
development property in ezcTemplateTranslationConfiguration that makes
the ezcTemplateTranslationProvider catch the Exceptions for missing
translations/translation files and just return the string from the
template. This solution makes it possible to develop with a template
that doesn't have a valid translation file yet.
Hmm, I see your point here; however, I don't quite think that this is an
elegant solution. I don't always want to catch the exception, and
rethrow it when the configure option is not set, nor having two bits of
code here for each case. Could you file a feature request for this
please?
regards,
setOptions( array ( 'format' => '[LOCALE].xml' ) );
// create ts file if it does not exist yet
createMissingTsFile( $backend->buildTranslationFileName( $locale ) );
$backend->initWriter( $locale );
foreach ( $it as $item )
{
$pathname = realpath( $item->getPathname() );
echo $pathname. "\n";
$contexts = getTranslationsFromTemplate( $item->getPathname() );
foreach ( $contexts AS $contextName => $translations )
{
try
{
// get the original context
$context = $backend->getContext( $locale, $contextName );
}
catch ( ezcTranslationContextNotAvailableException $e )
{
// create empty context
$context = array();
}
// store all existing translations in associative array
$translationMapOriginal = array();
foreach ( $context as $translationElement )
{
$translationMapOriginal[$translationElement->original] = $translationElement;
}
$translationMapNew = array();
foreach ( $translations as $translationElement )
{
$translationMapNew[$translationElement->original] = $translationElement;
}
// create empty context
$context = array();
// insert new translations
foreach ( $translations AS $translationElement )
{
// insert new strings
if ( !isset( $translationMapOriginal[$translationElement->original] ) )
{
$context[] = $translationElement;
}
}
// update translations
foreach ( $translationMapOriginal AS $translationElement )
{
// update data
if ( isset( $translationMapNew[$translationElement->original] ) )
{
$new = $translationMapNew[$translationElement->original];
$translationElement->comment = $new->comment;
$translationElement->filename = $new->filename;
$translationElement->line = $new->line;
$translationElement->column = $new->column;
$context[] = $translationElement;
}
// flag obsolete strings (only if filename is equal, because the context
// could be used in different files)
elseif ( $translationElement->filename == $pathname )
{
$translationElement->status = ezcTranslationData::OBSOLETE;
$context[] = $translationElement;
}
}
//var_dump( $context );
$backend->storeContext( $contextName, $context );
}
}
// write translation data to file
$backend->deinitWriter();
// format the xml to be readable
$file = str_replace( '\\', '/', $backend->buildTranslationFileName( $locale ) );
$xmllintPath = "C:/Program Files/gnuwin32/bin/";
$cmd = '"'.$xmllintPath.'xmllint" --format ' . $file;
file_put_contents( $file, shell_exec( $cmd ) );
/**
* Create missing ts file
*
* @param string $filename
*/
function createMissingTsFile( $filename )
{
if ( !is_file( $filename ) )
{
$content = '
';
file_put_contents( $filename, $content );
echo 'New Ts file created: ' . $file . "\n";
}
}
/**
* get translation array with translation data for each context from tpl
*
* @param string $filename
* @return @var array(string=>array(ezcTranslationData))
*/
function getTranslationsFromTemplate( $filename )
{
$source = new ezcTemplateSourceCode( $filename, $filename );
$source->load();
$parser = new ezcTemplateParser( $source, new ezcTemplate() );
$tst = $parser->parseIntoNodeTree();
$et = new ezcTemplateTranslationStringExtracter( $parser );
$eted = $tst->accept( $et );
return $et->strings;
}
/**
* RecursivFilterIterator that ignores '.svn' directories
*
*/
class IgnoreSvnDirIterator extends RecursiveFilterIterator
{
public function accept()
{
if ( $this->current()->getFilename() == '.svn' )
{
return false;
}
return true;
}
}
--
Components mailing list
[email protected]
http://lists.ez.no/mailman/listinfo/components