2015-08-17 17:00:26 -07:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\Translation\Loader ;
/**
* @ copyright Copyright ( c ) 2010 , Union of RAD http :// union - of - rad . org ( http :// lithify . me / )
* @ copyright Copyright ( c ) 2012 , Clemens Tolboom
*/
2016-04-20 09:56:34 -07:00
class PoFileLoader extends FileLoader
2015-08-17 17:00:26 -07:00
{
/**
* Parses portable object ( PO ) format .
*
* From http :// www . gnu . org / software / gettext / manual / gettext . html #PO-Files
* we should be able to parse files having :
*
* white - space
* # translator-comments
* #. extracted-comments
* #: reference...
* #, flag...
* #| msgid previous-untranslated-string
* msgid untranslated - string
* msgstr translated - string
*
* extra or different lines are :
*
* #| msgctxt previous-context
* #| msgid previous-untranslated-string
* msgctxt context
*
* #| msgid previous-untranslated-string-singular
* #| msgid_plural previous-untranslated-string-plural
* msgid untranslated - string - singular
* msgid_plural untranslated - string - plural
* msgstr [ 0 ] translated - string - case - 0
* ...
* msgstr [ N ] translated - string - case - n
*
* The definition states :
* - white - space and comments are optional .
* - msgid " " that an empty singleline defines a header .
*
* This parser sacrifices some features of the reference implementation the
* differences to that implementation are as follows .
* - No support for comments spanning multiple lines .
* - Translator and extracted comments are treated as being the same type .
* - Message IDs are allowed to have other encodings as just US - ASCII .
*
* Items with an empty id are ignored .
*
2016-04-20 09:56:34 -07:00
* { @ inheritdoc }
2015-08-17 17:00:26 -07:00
*/
2016-04-20 09:56:34 -07:00
protected function loadResource ( $resource )
2015-08-17 17:00:26 -07:00
{
$stream = fopen ( $resource , 'r' );
$defaults = array (
'ids' => array (),
'translated' => null ,
);
$messages = array ();
$item = $defaults ;
2016-04-20 09:56:34 -07:00
$flags = array ();
2015-08-17 17:00:26 -07:00
while ( $line = fgets ( $stream )) {
$line = trim ( $line );
2018-11-23 12:29:20 +00:00
if ( '' === $line ) {
2015-08-17 17:00:26 -07:00
// Whitespace indicated current item is done
2018-11-23 12:29:20 +00:00
if ( ! \in_array ( 'fuzzy' , $flags )) {
2016-04-20 09:56:34 -07:00
$this -> addMessage ( $messages , $item );
}
2015-08-17 17:00:26 -07:00
$item = $defaults ;
2016-04-20 09:56:34 -07:00
$flags = array ();
2018-11-23 12:29:20 +00:00
} elseif ( '#,' === substr ( $line , 0 , 2 )) {
2016-04-20 09:56:34 -07:00
$flags = array_map ( 'trim' , explode ( ',' , substr ( $line , 2 )));
2018-11-23 12:29:20 +00:00
} elseif ( 'msgid "' === substr ( $line , 0 , 7 )) {
2015-08-17 17:00:26 -07:00
// We start a new msg so save previous
// TODO: this fails when comments or contexts are added
$this -> addMessage ( $messages , $item );
$item = $defaults ;
$item [ 'ids' ][ 'singular' ] = substr ( $line , 7 , - 1 );
2018-11-23 12:29:20 +00:00
} elseif ( 'msgstr "' === substr ( $line , 0 , 8 )) {
2015-08-17 17:00:26 -07:00
$item [ 'translated' ] = substr ( $line , 8 , - 1 );
2018-11-23 12:29:20 +00:00
} elseif ( '"' === $line [ 0 ]) {
2015-08-17 17:00:26 -07:00
$continues = isset ( $item [ 'translated' ]) ? 'translated' : 'ids' ;
2018-11-23 12:29:20 +00:00
if ( \is_array ( $item [ $continues ])) {
2015-08-17 17:00:26 -07:00
end ( $item [ $continues ]);
$item [ $continues ][ key ( $item [ $continues ])] .= substr ( $line , 1 , - 1 );
} else {
$item [ $continues ] .= substr ( $line , 1 , - 1 );
}
2018-11-23 12:29:20 +00:00
} elseif ( 'msgid_plural "' === substr ( $line , 0 , 14 )) {
2015-08-17 17:00:26 -07:00
$item [ 'ids' ][ 'plural' ] = substr ( $line , 14 , - 1 );
2018-11-23 12:29:20 +00:00
} elseif ( 'msgstr[' === substr ( $line , 0 , 7 )) {
2015-08-17 17:00:26 -07:00
$size = strpos ( $line , ']' );
$item [ 'translated' ][( int ) substr ( $line , 7 , 1 )] = substr ( $line , $size + 3 , - 1 );
}
}
// save last item
2018-11-23 12:29:20 +00:00
if ( ! \in_array ( 'fuzzy' , $flags )) {
2016-04-20 09:56:34 -07:00
$this -> addMessage ( $messages , $item );
}
2015-08-17 17:00:26 -07:00
fclose ( $stream );
return $messages ;
}
/**
* Save a translation item to the messages .
*
* A . po file could contain by error missing plural indexes . We need to
* fix these before saving them .
*/
private function addMessage ( array & $messages , array $item )
{
2018-11-23 12:29:20 +00:00
if ( \is_array ( $item [ 'translated' ])) {
2015-08-17 17:00:26 -07:00
$messages [ stripcslashes ( $item [ 'ids' ][ 'singular' ])] = stripcslashes ( $item [ 'translated' ][ 0 ]);
if ( isset ( $item [ 'ids' ][ 'plural' ])) {
$plurals = $item [ 'translated' ];
// PO are by definition indexed so sort by index.
ksort ( $plurals );
// Make sure every index is filled.
end ( $plurals );
$count = key ( $plurals );
// Fill missing spots with '-'.
$empties = array_fill ( 0 , $count + 1 , '-' );
$plurals += $empties ;
ksort ( $plurals );
$messages [ stripcslashes ( $item [ 'ids' ][ 'plural' ])] = stripcslashes ( implode ( '|' , $plurals ));
}
} elseif ( ! empty ( $item [ 'ids' ][ 'singular' ])) {
$messages [ stripcslashes ( $item [ 'ids' ][ 'singular' ])] = stripcslashes ( $item [ 'translated' ]);
}
}
}