Make WordPress Core


Ignore:
Timestamp:
11/30/2017 11:09:33 PM (6 years ago)
Author:
pento
Message:

Code is Poetry.
WordPress' code just... wasn't.
This is now dealt with.

Props jrf, pento, netweb, GaryJ, jdgrimes, westonruter, Greg Sherwood from PHPCS, and everyone who's ever contributed to WPCS and PHPCS.
Fixes #41057.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/pomo/po.php

    r41686 r42343  
    88 */
    99
    10 require_once dirname(__FILE__) . '/translations.php';
     10require_once dirname( __FILE__ ) . '/translations.php';
    1111
    1212if ( ! defined( 'PO_MAX_LINE_LEN' ) ) {
    13     define('PO_MAX_LINE_LEN', 79);
     13    define( 'PO_MAX_LINE_LEN', 79 );
    1414}
    1515
    16 ini_set('auto_detect_line_endings', 1);
     16ini_set( 'auto_detect_line_endings', 1 );
    1717
    1818/**
    1919 * Routines for working with PO files
    2020 */
    21 if ( ! class_exists( 'PO', false ) ):
    22 class PO extends Gettext_Translations {
    23 
    24     var $comments_before_headers = '';
    25 
    26     /**
    27      * Exports headers to a PO entry
    28      *
    29      * @return string msgid/msgstr PO entry for this PO file headers, doesn't contain newline at the end
    30      */
    31     function export_headers() {
    32         $header_string = '';
    33         foreach($this->headers as $header => $value) {
    34             $header_string.= "$header: $value\n";
    35         }
    36         $poified = PO::poify($header_string);
    37         if ($this->comments_before_headers)
    38             $before_headers = $this->prepend_each_line(rtrim($this->comments_before_headers)."\n", '# ');
    39         else
    40             $before_headers = '';
    41         return rtrim("{$before_headers}msgid \"\"\nmsgstr $poified");
    42     }
    43 
    44     /**
    45      * Exports all entries to PO format
    46      *
    47      * @return string sequence of mgsgid/msgstr PO strings, doesn't containt newline at the end
    48      */
    49     function export_entries() {
    50         //TODO sorting
    51         return implode("\n\n", array_map(array('PO', 'export_entry'), $this->entries));
    52     }
    53 
    54     /**
    55      * Exports the whole PO file as a string
    56      *
    57      * @param bool $include_headers whether to include the headers in the export
    58      * @return string ready for inclusion in PO file string for headers and all the enrtries
    59      */
    60     function export($include_headers = true) {
    61         $res = '';
    62         if ($include_headers) {
    63             $res .= $this->export_headers();
    64             $res .= "\n\n";
    65         }
    66         $res .= $this->export_entries();
    67         return $res;
    68     }
    69 
    70     /**
    71      * Same as {@link export}, but writes the result to a file
    72      *
    73      * @param string $filename where to write the PO string
    74      * @param bool $include_headers whether to include tje headers in the export
    75      * @return bool true on success, false on error
    76      */
    77     function export_to_file($filename, $include_headers = true) {
    78         $fh = fopen($filename, 'w');
    79         if (false === $fh) return false;
    80         $export = $this->export($include_headers);
    81         $res = fwrite($fh, $export);
    82         if (false === $res) return false;
    83         return fclose($fh);
    84     }
    85 
    86     /**
    87      * Text to include as a comment before the start of the PO contents
    88      *
    89      * Doesn't need to include # in the beginning of lines, these are added automatically
    90      */
    91     function set_comment_before_headers( $text ) {
    92         $this->comments_before_headers = $text;
    93     }
    94 
    95     /**
    96      * Formats a string in PO-style
    97      *
    98      * @static
    99      * @param string $string the string to format
    100      * @return string the poified string
    101      */
    102     public static function poify($string) {
    103         $quote = '"';
    104         $slash = '\\';
    105         $newline = "\n";
    106 
    107         $replaces = array(
    108             "$slash"    => "$slash$slash",
    109             "$quote"    => "$slash$quote",
    110             "\t"        => '\t',
    111         );
    112 
    113         $string = str_replace(array_keys($replaces), array_values($replaces), $string);
    114 
    115         $po = $quote.implode("${slash}n$quote$newline$quote", explode($newline, $string)).$quote;
    116         // add empty string on first line for readbility
    117         if (false !== strpos($string, $newline) &&
    118                 (substr_count($string, $newline) > 1 || !($newline === substr($string, -strlen($newline))))) {
    119             $po = "$quote$quote$newline$po";
    120         }
    121         // remove empty strings
    122         $po = str_replace("$newline$quote$quote", '', $po);
    123         return $po;
    124     }
    125 
    126     /**
    127      * Gives back the original string from a PO-formatted string
    128      *
    129      * @static
    130      * @param string $string PO-formatted string
    131      * @return string enascaped string
    132      */
    133     public static function unpoify($string) {
    134         $escapes = array('t' => "\t", 'n' => "\n", 'r' => "\r", '\\' => '\\');
    135         $lines = array_map('trim', explode("\n", $string));
    136         $lines = array_map(array('PO', 'trim_quotes'), $lines);
    137         $unpoified = '';
    138         $previous_is_backslash = false;
    139         foreach($lines as $line) {
    140             preg_match_all('/./u', $line, $chars);
    141             $chars = $chars[0];
    142             foreach($chars as $char) {
    143                 if (!$previous_is_backslash) {
    144                     if ('\\' == $char)
    145                         $previous_is_backslash = true;
    146                     else
    147                         $unpoified .= $char;
     21if ( ! class_exists( 'PO', false ) ) :
     22    class PO extends Gettext_Translations {
     23
     24        var $comments_before_headers = '';
     25
     26        /**
     27         * Exports headers to a PO entry
     28         *
     29         * @return string msgid/msgstr PO entry for this PO file headers, doesn't contain newline at the end
     30         */
     31        function export_headers() {
     32            $header_string = '';
     33            foreach ( $this->headers as $header => $value ) {
     34                $header_string .= "$header: $value\n";
     35            }
     36            $poified = PO::poify( $header_string );
     37            if ( $this->comments_before_headers ) {
     38                $before_headers = $this->prepend_each_line( rtrim( $this->comments_before_headers ) . "\n", '# ' );
     39            } else {
     40                $before_headers = '';
     41            }
     42            return rtrim( "{$before_headers}msgid \"\"\nmsgstr $poified" );
     43        }
     44
     45        /**
     46         * Exports all entries to PO format
     47         *
     48         * @return string sequence of mgsgid/msgstr PO strings, doesn't containt newline at the end
     49         */
     50        function export_entries() {
     51            //TODO sorting
     52            return implode( "\n\n", array_map( array( 'PO', 'export_entry' ), $this->entries ) );
     53        }
     54
     55        /**
     56         * Exports the whole PO file as a string
     57         *
     58         * @param bool $include_headers whether to include the headers in the export
     59         * @return string ready for inclusion in PO file string for headers and all the enrtries
     60         */
     61        function export( $include_headers = true ) {
     62            $res = '';
     63            if ( $include_headers ) {
     64                $res .= $this->export_headers();
     65                $res .= "\n\n";
     66            }
     67            $res .= $this->export_entries();
     68            return $res;
     69        }
     70
     71        /**
     72         * Same as {@link export}, but writes the result to a file
     73         *
     74         * @param string $filename where to write the PO string
     75         * @param bool $include_headers whether to include tje headers in the export
     76         * @return bool true on success, false on error
     77         */
     78        function export_to_file( $filename, $include_headers = true ) {
     79            $fh = fopen( $filename, 'w' );
     80            if ( false === $fh ) {
     81                return false;
     82            }
     83            $export = $this->export( $include_headers );
     84            $res    = fwrite( $fh, $export );
     85            if ( false === $res ) {
     86                return false;
     87            }
     88            return fclose( $fh );
     89        }
     90
     91        /**
     92         * Text to include as a comment before the start of the PO contents
     93         *
     94         * Doesn't need to include # in the beginning of lines, these are added automatically
     95         */
     96        function set_comment_before_headers( $text ) {
     97            $this->comments_before_headers = $text;
     98        }
     99
     100        /**
     101         * Formats a string in PO-style
     102         *
     103         * @static
     104         * @param string $string the string to format
     105         * @return string the poified string
     106         */
     107        public static function poify( $string ) {
     108            $quote   = '"';
     109            $slash   = '\\';
     110            $newline = "\n";
     111
     112            $replaces = array(
     113                "$slash" => "$slash$slash",
     114                "$quote" => "$slash$quote",
     115                "\t"     => '\t',
     116            );
     117
     118            $string = str_replace( array_keys( $replaces ), array_values( $replaces ), $string );
     119
     120            $po = $quote . implode( "${slash}n$quote$newline$quote", explode( $newline, $string ) ) . $quote;
     121            // add empty string on first line for readbility
     122            if ( false !== strpos( $string, $newline ) &&
     123                ( substr_count( $string, $newline ) > 1 || ! ( $newline === substr( $string, -strlen( $newline ) ) ) ) ) {
     124                $po = "$quote$quote$newline$po";
     125            }
     126            // remove empty strings
     127            $po = str_replace( "$newline$quote$quote", '', $po );
     128            return $po;
     129        }
     130
     131        /**
     132         * Gives back the original string from a PO-formatted string
     133         *
     134         * @static
     135         * @param string $string PO-formatted string
     136         * @return string enascaped string
     137         */
     138        public static function unpoify( $string ) {
     139            $escapes               = array(
     140                't'  => "\t",
     141                'n'  => "\n",
     142                'r'  => "\r",
     143                '\\' => '\\',
     144            );
     145            $lines                 = array_map( 'trim', explode( "\n", $string ) );
     146            $lines                 = array_map( array( 'PO', 'trim_quotes' ), $lines );
     147            $unpoified             = '';
     148            $previous_is_backslash = false;
     149            foreach ( $lines as $line ) {
     150                preg_match_all( '/./u', $line, $chars );
     151                $chars = $chars[0];
     152                foreach ( $chars as $char ) {
     153                    if ( ! $previous_is_backslash ) {
     154                        if ( '\\' == $char ) {
     155                            $previous_is_backslash = true;
     156                        } else {
     157                            $unpoified .= $char;
     158                        }
     159                    } else {
     160                        $previous_is_backslash = false;
     161                        $unpoified            .= isset( $escapes[ $char ] ) ? $escapes[ $char ] : $char;
     162                    }
     163                }
     164            }
     165
     166            // Standardise the line endings on imported content, technically PO files shouldn't contain \r
     167            $unpoified = str_replace( array( "\r\n", "\r" ), "\n", $unpoified );
     168
     169            return $unpoified;
     170        }
     171
     172        /**
     173         * Inserts $with in the beginning of every new line of $string and
     174         * returns the modified string
     175         *
     176         * @static
     177         * @param string $string prepend lines in this string
     178         * @param string $with prepend lines with this string
     179         */
     180        public static function prepend_each_line( $string, $with ) {
     181            $lines  = explode( "\n", $string );
     182            $append = '';
     183            if ( "\n" === substr( $string, -1 ) && '' === end( $lines ) ) {
     184                // Last line might be empty because $string was terminated
     185                // with a newline, remove it from the $lines array,
     186                // we'll restore state by re-terminating the string at the end
     187                array_pop( $lines );
     188                $append = "\n";
     189            }
     190            foreach ( $lines as &$line ) {
     191                $line = $with . $line;
     192            }
     193            unset( $line );
     194            return implode( "\n", $lines ) . $append;
     195        }
     196
     197        /**
     198         * Prepare a text as a comment -- wraps the lines and prepends #
     199         * and a special character to each line
     200         *
     201         * @access private
     202         * @param string $text the comment text
     203         * @param string $char character to denote a special PO comment,
     204         *  like :, default is a space
     205         */
     206        public static function comment_block( $text, $char = ' ' ) {
     207            $text = wordwrap( $text, PO_MAX_LINE_LEN - 3 );
     208            return PO::prepend_each_line( $text, "#$char " );
     209        }
     210
     211        /**
     212         * Builds a string from the entry for inclusion in PO file
     213         *
     214         * @static
     215         * @param Translation_Entry $entry the entry to convert to po string (passed by reference).
     216         * @return false|string PO-style formatted string for the entry or
     217         *  false if the entry is empty
     218         */
     219        public static function export_entry( &$entry ) {
     220            if ( null === $entry->singular || '' === $entry->singular ) {
     221                return false;
     222            }
     223            $po = array();
     224            if ( ! empty( $entry->translator_comments ) ) {
     225                $po[] = PO::comment_block( $entry->translator_comments );
     226            }
     227            if ( ! empty( $entry->extracted_comments ) ) {
     228                $po[] = PO::comment_block( $entry->extracted_comments, '.' );
     229            }
     230            if ( ! empty( $entry->references ) ) {
     231                $po[] = PO::comment_block( implode( ' ', $entry->references ), ':' );
     232            }
     233            if ( ! empty( $entry->flags ) ) {
     234                $po[] = PO::comment_block( implode( ', ', $entry->flags ), ',' );
     235            }
     236            if ( $entry->context ) {
     237                $po[] = 'msgctxt ' . PO::poify( $entry->context );
     238            }
     239            $po[] = 'msgid ' . PO::poify( $entry->singular );
     240            if ( ! $entry->is_plural ) {
     241                $translation = empty( $entry->translations ) ? '' : $entry->translations[0];
     242                $translation = PO::match_begin_and_end_newlines( $translation, $entry->singular );
     243                $po[]        = 'msgstr ' . PO::poify( $translation );
     244            } else {
     245                $po[]         = 'msgid_plural ' . PO::poify( $entry->plural );
     246                $translations = empty( $entry->translations ) ? array( '', '' ) : $entry->translations;
     247                foreach ( $translations as $i => $translation ) {
     248                    $translation = PO::match_begin_and_end_newlines( $translation, $entry->plural );
     249                    $po[]        = "msgstr[$i] " . PO::poify( $translation );
     250                }
     251            }
     252            return implode( "\n", $po );
     253        }
     254
     255        public static function match_begin_and_end_newlines( $translation, $original ) {
     256            if ( '' === $translation ) {
     257                return $translation;
     258            }
     259
     260            $original_begin    = "\n" === substr( $original, 0, 1 );
     261            $original_end      = "\n" === substr( $original, -1 );
     262            $translation_begin = "\n" === substr( $translation, 0, 1 );
     263            $translation_end   = "\n" === substr( $translation, -1 );
     264
     265            if ( $original_begin ) {
     266                if ( ! $translation_begin ) {
     267                    $translation = "\n" . $translation;
     268                }
     269            } elseif ( $translation_begin ) {
     270                $translation = ltrim( $translation, "\n" );
     271            }
     272
     273            if ( $original_end ) {
     274                if ( ! $translation_end ) {
     275                    $translation .= "\n";
     276                }
     277            } elseif ( $translation_end ) {
     278                $translation = rtrim( $translation, "\n" );
     279            }
     280
     281            return $translation;
     282        }
     283
     284        /**
     285         * @param string $filename
     286         * @return boolean
     287         */
     288        function import_from_file( $filename ) {
     289            $f = fopen( $filename, 'r' );
     290            if ( ! $f ) {
     291                return false;
     292            }
     293            $lineno = 0;
     294            while ( true ) {
     295                $res = $this->read_entry( $f, $lineno );
     296                if ( ! $res ) {
     297                    break;
     298                }
     299                if ( $res['entry']->singular == '' ) {
     300                    $this->set_headers( $this->make_headers( $res['entry']->translations[0] ) );
    148301                } else {
    149                     $previous_is_backslash = false;
    150                     $unpoified .= isset($escapes[$char])? $escapes[$char] : $char;
    151                 }
    152             }
    153         }
    154 
    155         // Standardise the line endings on imported content, technically PO files shouldn't contain \r
    156         $unpoified = str_replace( array( "\r\n", "\r" ), "\n", $unpoified );
    157 
    158         return $unpoified;
    159     }
    160 
    161     /**
    162      * Inserts $with in the beginning of every new line of $string and
    163      * returns the modified string
    164      *
    165      * @static
    166      * @param string $string prepend lines in this string
    167      * @param string $with prepend lines with this string
    168      */
    169     public static function prepend_each_line($string, $with) {
    170         $lines = explode("\n", $string);
    171         $append = '';
    172         if ("\n" === substr($string, -1) && '' === end($lines)) {
    173             // Last line might be empty because $string was terminated
    174             // with a newline, remove it from the $lines array,
    175             // we'll restore state by re-terminating the string at the end
    176             array_pop($lines);
    177             $append = "\n";
    178         }
    179         foreach ($lines as &$line) {
    180             $line = $with . $line;
    181         }
    182         unset($line);
    183         return implode("\n", $lines) . $append;
    184     }
    185 
    186     /**
    187      * Prepare a text as a comment -- wraps the lines and prepends #
    188      * and a special character to each line
    189      *
    190      * @access private
    191      * @param string $text the comment text
    192      * @param string $char character to denote a special PO comment,
    193      *  like :, default is a space
    194      */
    195     public static function comment_block($text, $char=' ') {
    196         $text = wordwrap($text, PO_MAX_LINE_LEN - 3);
    197         return PO::prepend_each_line($text, "#$char ");
    198     }
    199 
    200     /**
    201      * Builds a string from the entry for inclusion in PO file
    202      *
    203      * @static
    204      * @param Translation_Entry $entry the entry to convert to po string (passed by reference).
    205      * @return false|string PO-style formatted string for the entry or
    206      *  false if the entry is empty
    207      */
    208     public static function export_entry(&$entry) {
    209         if ( null === $entry->singular || '' === $entry->singular ) return false;
    210         $po = array();
    211         if (!empty($entry->translator_comments)) $po[] = PO::comment_block($entry->translator_comments);
    212         if (!empty($entry->extracted_comments)) $po[] = PO::comment_block($entry->extracted_comments, '.');
    213         if (!empty($entry->references)) $po[] = PO::comment_block(implode(' ', $entry->references), ':');
    214         if (!empty($entry->flags)) $po[] = PO::comment_block(implode(", ", $entry->flags), ',');
    215         if ($entry->context) $po[] = 'msgctxt '.PO::poify($entry->context);
    216         $po[] = 'msgid '.PO::poify($entry->singular);
    217         if (!$entry->is_plural) {
    218             $translation = empty($entry->translations)? '' : $entry->translations[0];
    219             $translation = PO::match_begin_and_end_newlines( $translation, $entry->singular );
    220             $po[] = 'msgstr '.PO::poify($translation);
    221         } else {
    222             $po[] = 'msgid_plural '.PO::poify($entry->plural);
    223             $translations = empty($entry->translations)? array('', '') : $entry->translations;
    224             foreach($translations as $i => $translation) {
    225                 $translation = PO::match_begin_and_end_newlines( $translation, $entry->plural );
    226                 $po[] = "msgstr[$i] ".PO::poify($translation);
    227             }
    228         }
    229         return implode("\n", $po);
    230     }
    231 
    232     public static function match_begin_and_end_newlines( $translation, $original ) {
    233         if ( '' === $translation ) {
    234             return $translation;
    235         }
    236 
    237         $original_begin = "\n" === substr( $original, 0, 1 );
    238         $original_end = "\n" === substr( $original, -1 );
    239         $translation_begin = "\n" === substr( $translation, 0, 1 );
    240         $translation_end = "\n" === substr( $translation, -1 );
    241 
    242         if ( $original_begin ) {
    243             if ( ! $translation_begin ) {
    244                 $translation = "\n" . $translation;
    245             }
    246         } elseif ( $translation_begin ) {
    247             $translation = ltrim( $translation, "\n" );
    248         }
    249 
    250         if ( $original_end ) {
    251             if ( ! $translation_end ) {
    252                 $translation .= "\n";
    253             }
    254         } elseif ( $translation_end ) {
    255             $translation = rtrim( $translation, "\n" );
    256         }
    257 
    258         return $translation;
    259     }
    260 
    261     /**
    262      * @param string $filename
    263      * @return boolean
    264      */
    265     function import_from_file($filename) {
    266         $f = fopen($filename, 'r');
    267         if (!$f) return false;
    268         $lineno = 0;
    269         while (true) {
    270             $res = $this->read_entry($f, $lineno);
    271             if (!$res) break;
    272             if ($res['entry']->singular == '') {
    273                 $this->set_headers($this->make_headers($res['entry']->translations[0]));
    274             } else {
    275                 $this->add_entry($res['entry']);
    276             }
    277         }
    278         PO::read_line($f, 'clear');
    279         if ( false === $res ) {
    280             return false;
    281         }
    282         if ( ! $this->headers && ! $this->entries ) {
    283             return false;
    284         }
    285         return true;
    286     }
    287 
    288     /**
    289      * Helper function for read_entry
    290      * @param string $context
    291      * @return bool
    292      */
    293     protected static function is_final($context) {
    294         return ($context === 'msgstr') || ($context === 'msgstr_plural');
    295     }
    296 
    297     /**
    298      * @param resource $f
    299      * @param int      $lineno
    300      * @return null|false|array
    301      */
    302     function read_entry($f, $lineno = 0) {
    303         $entry = new Translation_Entry();
    304         // where were we in the last step
    305         // can be: comment, msgctxt, msgid, msgid_plural, msgstr, msgstr_plural
    306         $context = '';
    307         $msgstr_index = 0;
    308         while (true) {
    309             $lineno++;
    310             $line = PO::read_line($f);
    311             if (!$line)  {
    312                 if (feof($f)) {
    313                     if (self::is_final($context))
     302                    $this->add_entry( $res['entry'] );
     303                }
     304            }
     305            PO::read_line( $f, 'clear' );
     306            if ( false === $res ) {
     307                return false;
     308            }
     309            if ( ! $this->headers && ! $this->entries ) {
     310                return false;
     311            }
     312            return true;
     313        }
     314
     315        /**
     316         * Helper function for read_entry
     317         *
     318         * @param string $context
     319         * @return bool
     320         */
     321        protected static function is_final( $context ) {
     322            return ( $context === 'msgstr' ) || ( $context === 'msgstr_plural' );
     323        }
     324
     325        /**
     326         * @param resource $f
     327         * @param int      $lineno
     328         * @return null|false|array
     329         */
     330        function read_entry( $f, $lineno = 0 ) {
     331            $entry = new Translation_Entry();
     332            // where were we in the last step
     333            // can be: comment, msgctxt, msgid, msgid_plural, msgstr, msgstr_plural
     334            $context      = '';
     335            $msgstr_index = 0;
     336            while ( true ) {
     337                $lineno++;
     338                $line = PO::read_line( $f );
     339                if ( ! $line ) {
     340                    if ( feof( $f ) ) {
     341                        if ( self::is_final( $context ) ) {
     342                            break;
     343                        } elseif ( ! $context ) { // we haven't read a line and eof came
     344                            return null;
     345                        } else {
     346                            return false;
     347                        }
     348                    } else {
     349                        return false;
     350                    }
     351                }
     352                if ( $line == "\n" ) {
     353                    continue;
     354                }
     355                $line = trim( $line );
     356                if ( preg_match( '/^#/', $line, $m ) ) {
     357                    // the comment is the start of a new entry
     358                    if ( self::is_final( $context ) ) {
     359                        PO::read_line( $f, 'put-back' );
     360                        $lineno--;
    314361                        break;
    315                     elseif (!$context) // we haven't read a line and eof came
    316                         return null;
    317                     else
    318                         return false;
     362                    }
     363                    // comments have to be at the beginning
     364                    if ( $context && $context != 'comment' ) {
     365                        return false;
     366                    }
     367                    // add comment
     368                    $this->add_comment_to_entry( $entry, $line );
     369                } elseif ( preg_match( '/^msgctxt\s+(".*")/', $line, $m ) ) {
     370                    if ( self::is_final( $context ) ) {
     371                        PO::read_line( $f, 'put-back' );
     372                        $lineno--;
     373                        break;
     374                    }
     375                    if ( $context && $context != 'comment' ) {
     376                        return false;
     377                    }
     378                    $context         = 'msgctxt';
     379                    $entry->context .= PO::unpoify( $m[1] );
     380                } elseif ( preg_match( '/^msgid\s+(".*")/', $line, $m ) ) {
     381                    if ( self::is_final( $context ) ) {
     382                        PO::read_line( $f, 'put-back' );
     383                        $lineno--;
     384                        break;
     385                    }
     386                    if ( $context && $context != 'msgctxt' && $context != 'comment' ) {
     387                        return false;
     388                    }
     389                    $context          = 'msgid';
     390                    $entry->singular .= PO::unpoify( $m[1] );
     391                } elseif ( preg_match( '/^msgid_plural\s+(".*")/', $line, $m ) ) {
     392                    if ( $context != 'msgid' ) {
     393                        return false;
     394                    }
     395                    $context          = 'msgid_plural';
     396                    $entry->is_plural = true;
     397                    $entry->plural   .= PO::unpoify( $m[1] );
     398                } elseif ( preg_match( '/^msgstr\s+(".*")/', $line, $m ) ) {
     399                    if ( $context != 'msgid' ) {
     400                        return false;
     401                    }
     402                    $context             = 'msgstr';
     403                    $entry->translations = array( PO::unpoify( $m[1] ) );
     404                } elseif ( preg_match( '/^msgstr\[(\d+)\]\s+(".*")/', $line, $m ) ) {
     405                    if ( $context != 'msgid_plural' && $context != 'msgstr_plural' ) {
     406                        return false;
     407                    }
     408                    $context                      = 'msgstr_plural';
     409                    $msgstr_index                 = $m[1];
     410                    $entry->translations[ $m[1] ] = PO::unpoify( $m[2] );
     411                } elseif ( preg_match( '/^".*"$/', $line ) ) {
     412                    $unpoified = PO::unpoify( $line );
     413                    switch ( $context ) {
     414                        case 'msgid':
     415                            $entry->singular .= $unpoified;
     416                            break;
     417                        case 'msgctxt':
     418                            $entry->context .= $unpoified;
     419                            break;
     420                        case 'msgid_plural':
     421                            $entry->plural .= $unpoified;
     422                            break;
     423                        case 'msgstr':
     424                            $entry->translations[0] .= $unpoified;
     425                            break;
     426                        case 'msgstr_plural':
     427                            $entry->translations[ $msgstr_index ] .= $unpoified;
     428                            break;
     429                        default:
     430                            return false;
     431                    }
    319432                } else {
    320433                    return false;
    321434                }
    322435            }
    323             if ($line == "\n") continue;
    324             $line = trim($line);
    325             if (preg_match('/^#/', $line, $m)) {
    326                 // the comment is the start of a new entry
    327                 if (self::is_final($context)) {
    328                     PO::read_line($f, 'put-back');
    329                     $lineno--;
     436
     437            $have_translations = false;
     438            foreach ( $entry->translations as $t ) {
     439                if ( $t || ( '0' === $t ) ) {
     440                    $have_translations = true;
    330441                    break;
    331442                }
    332                 // comments have to be at the beginning
    333                 if ($context && $context != 'comment') {
    334                     return false;
    335                 }
    336                 // add comment
    337                 $this->add_comment_to_entry($entry, $line);
    338             } elseif (preg_match('/^msgctxt\s+(".*")/', $line, $m)) {
    339                 if (self::is_final($context)) {
    340                     PO::read_line($f, 'put-back');
    341                     $lineno--;
    342                     break;
    343                 }
    344                 if ($context && $context != 'comment') {
    345                     return false;
    346                 }
    347                 $context = 'msgctxt';
    348                 $entry->context .= PO::unpoify($m[1]);
    349             } elseif (preg_match('/^msgid\s+(".*")/', $line, $m)) {
    350                 if (self::is_final($context)) {
    351                     PO::read_line($f, 'put-back');
    352                     $lineno--;
    353                     break;
    354                 }
    355                 if ($context && $context != 'msgctxt' && $context != 'comment') {
    356                     return false;
    357                 }
    358                 $context = 'msgid';
    359                 $entry->singular .= PO::unpoify($m[1]);
    360             } elseif (preg_match('/^msgid_plural\s+(".*")/', $line, $m)) {
    361                 if ($context != 'msgid') {
    362                     return false;
    363                 }
    364                 $context = 'msgid_plural';
    365                 $entry->is_plural = true;
    366                 $entry->plural .= PO::unpoify($m[1]);
    367             } elseif (preg_match('/^msgstr\s+(".*")/', $line, $m)) {
    368                 if ($context != 'msgid') {
    369                     return false;
    370                 }
    371                 $context = 'msgstr';
    372                 $entry->translations = array(PO::unpoify($m[1]));
    373             } elseif (preg_match('/^msgstr\[(\d+)\]\s+(".*")/', $line, $m)) {
    374                 if ($context != 'msgid_plural' && $context != 'msgstr_plural') {
    375                     return false;
    376                 }
    377                 $context = 'msgstr_plural';
    378                 $msgstr_index = $m[1];
    379                 $entry->translations[$m[1]] = PO::unpoify($m[2]);
    380             } elseif (preg_match('/^".*"$/', $line)) {
    381                 $unpoified = PO::unpoify($line);
    382                 switch ($context) {
    383                     case 'msgid':
    384                         $entry->singular .= $unpoified; break;
    385                     case 'msgctxt':
    386                         $entry->context .= $unpoified; break;
    387                     case 'msgid_plural':
    388                         $entry->plural .= $unpoified; break;
    389                     case 'msgstr':
    390                         $entry->translations[0] .= $unpoified; break;
    391                     case 'msgstr_plural':
    392                         $entry->translations[$msgstr_index] .= $unpoified; break;
    393                     default:
    394                         return false;
    395                 }
     443            }
     444            if ( false === $have_translations ) {
     445                $entry->translations = array();
     446            }
     447
     448            return array(
     449                'entry'  => $entry,
     450                'lineno' => $lineno,
     451            );
     452        }
     453
     454        /**
     455         * @staticvar string   $last_line
     456         * @staticvar boolean  $use_last_line
     457         *
     458         * @param     resource $f
     459         * @param     string   $action
     460         * @return boolean
     461         */
     462        function read_line( $f, $action = 'read' ) {
     463            static $last_line     = '';
     464            static $use_last_line = false;
     465            if ( 'clear' == $action ) {
     466                $last_line = '';
     467                return true;
     468            }
     469            if ( 'put-back' == $action ) {
     470                $use_last_line = true;
     471                return true;
     472            }
     473            $line          = $use_last_line ? $last_line : fgets( $f );
     474            $line          = ( "\r\n" == substr( $line, -2 ) ) ? rtrim( $line, "\r\n" ) . "\n" : $line;
     475            $last_line     = $line;
     476            $use_last_line = false;
     477            return $line;
     478        }
     479
     480        /**
     481         * @param Translation_Entry $entry
     482         * @param string            $po_comment_line
     483         */
     484        function add_comment_to_entry( &$entry, $po_comment_line ) {
     485            $first_two = substr( $po_comment_line, 0, 2 );
     486            $comment   = trim( substr( $po_comment_line, 2 ) );
     487            if ( '#:' == $first_two ) {
     488                $entry->references = array_merge( $entry->references, preg_split( '/\s+/', $comment ) );
     489            } elseif ( '#.' == $first_two ) {
     490                $entry->extracted_comments = trim( $entry->extracted_comments . "\n" . $comment );
     491            } elseif ( '#,' == $first_two ) {
     492                $entry->flags = array_merge( $entry->flags, preg_split( '/,\s*/', $comment ) );
    396493            } else {
    397                 return false;
    398             }
    399         }
    400 
    401         $have_translations = false;
    402         foreach ( $entry->translations as $t ) {
    403             if ( $t || ('0' === $t) ) {
    404                 $have_translations = true;
    405                 break;
    406             }
    407         }
    408         if ( false === $have_translations ) {
    409             $entry->translations = array();
    410         }
    411 
    412         return array('entry' => $entry, 'lineno' => $lineno);
     494                $entry->translator_comments = trim( $entry->translator_comments . "\n" . $comment );
     495            }
     496        }
     497
     498        /**
     499         * @param string $s
     500         * @return sring
     501         */
     502        public static function trim_quotes( $s ) {
     503            if ( substr( $s, 0, 1 ) == '"' ) {
     504                $s = substr( $s, 1 );
     505            }
     506            if ( substr( $s, -1, 1 ) == '"' ) {
     507                $s = substr( $s, 0, -1 );
     508            }
     509            return $s;
     510        }
    413511    }
    414 
    415     /**
    416      * @staticvar string   $last_line
    417      * @staticvar boolean  $use_last_line
    418      *
    419      * @param     resource $f
    420      * @param     string   $action
    421      * @return boolean
    422      */
    423     function read_line($f, $action = 'read') {
    424         static $last_line = '';
    425         static $use_last_line = false;
    426         if ('clear' == $action) {
    427             $last_line = '';
    428             return true;
    429         }
    430         if ('put-back' == $action) {
    431             $use_last_line = true;
    432             return true;
    433         }
    434         $line = $use_last_line? $last_line : fgets($f);
    435         $line = ( "\r\n" == substr( $line, -2 ) ) ? rtrim( $line, "\r\n" ) . "\n" : $line;
    436         $last_line = $line;
    437         $use_last_line = false;
    438         return $line;
    439     }
    440 
    441     /**
    442      * @param Translation_Entry $entry
    443      * @param string            $po_comment_line
    444      */
    445     function add_comment_to_entry(&$entry, $po_comment_line) {
    446         $first_two = substr($po_comment_line, 0, 2);
    447         $comment = trim(substr($po_comment_line, 2));
    448         if ('#:' == $first_two) {
    449             $entry->references = array_merge($entry->references, preg_split('/\s+/', $comment));
    450         } elseif ('#.' == $first_two) {
    451             $entry->extracted_comments = trim($entry->extracted_comments . "\n" . $comment);
    452         } elseif ('#,' == $first_two) {
    453             $entry->flags = array_merge($entry->flags, preg_split('/,\s*/', $comment));
    454         } else {
    455             $entry->translator_comments = trim($entry->translator_comments . "\n" . $comment);
    456         }
    457     }
    458 
    459     /**
    460      * @param string $s
    461      * @return sring
    462      */
    463     public static function trim_quotes($s) {
    464         if ( substr($s, 0, 1) == '"') $s = substr($s, 1);
    465         if ( substr($s, -1, 1) == '"') $s = substr($s, 0, -1);
    466         return $s;
    467     }
    468 }
    469512endif;
Note: See TracChangeset for help on using the changeset viewer.