Make WordPress Core


Ignore:
Timestamp:
11/30/2017 11:09:33 PM (9 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/translations.php

    r41722 r42343  
    88 */
    99
    10 require_once dirname(__FILE__) . '/plural-forms.php';
    11 require_once dirname(__FILE__) . '/entry.php';
    12 
    13 if ( ! class_exists( 'Translations', false ) ):
    14 class Translations {
    15         var $entries = array();
    16         var $headers = array();
    17 
     10require_once dirname( __FILE__ ) . '/plural-forms.php';
     11require_once dirname( __FILE__ ) . '/entry.php';
     12
     13if ( ! class_exists( 'Translations', false ) ) :
     14        class Translations {
     15                var $entries = array();
     16                var $headers = array();
     17
     18                /**
     19                 * Add entry to the PO structure
     20                 *
     21                 * @param array|Translation_Entry $entry
     22                 * @return bool true on success, false if the entry doesn't have a key
     23                 */
     24                function add_entry( $entry ) {
     25                        if ( is_array( $entry ) ) {
     26                                $entry = new Translation_Entry( $entry );
     27                        }
     28                        $key = $entry->key();
     29                        if ( false === $key ) {
     30                                return false;
     31                        }
     32                        $this->entries[ $key ] = &$entry;
     33                        return true;
     34                }
     35
     36                /**
     37                 * @param array|Translation_Entry $entry
     38                 * @return bool
     39                 */
     40                function add_entry_or_merge( $entry ) {
     41                        if ( is_array( $entry ) ) {
     42                                $entry = new Translation_Entry( $entry );
     43                        }
     44                        $key = $entry->key();
     45                        if ( false === $key ) {
     46                                return false;
     47                        }
     48                        if ( isset( $this->entries[ $key ] ) ) {
     49                                $this->entries[ $key ]->merge_with( $entry );
     50                        } else {
     51                                $this->entries[ $key ] = &$entry;
     52                        }
     53                        return true;
     54                }
     55
     56                /**
     57                 * Sets $header PO header to $value
     58                 *
     59                 * If the header already exists, it will be overwritten
     60                 *
     61                 * TODO: this should be out of this class, it is gettext specific
     62                 *
     63                 * @param string $header header name, without trailing :
     64                 * @param string $value header value, without trailing \n
     65                 */
     66                function set_header( $header, $value ) {
     67                        $this->headers[ $header ] = $value;
     68                }
     69
     70                /**
     71                 * @param array $headers
     72                 */
     73                function set_headers( $headers ) {
     74                        foreach ( $headers as $header => $value ) {
     75                                $this->set_header( $header, $value );
     76                        }
     77                }
     78
     79                /**
     80                 * @param string $header
     81                 */
     82                function get_header( $header ) {
     83                        return isset( $this->headers[ $header ] ) ? $this->headers[ $header ] : false;
     84                }
     85
     86                /**
     87                 * @param Translation_Entry $entry
     88                 */
     89                function translate_entry( &$entry ) {
     90                        $key = $entry->key();
     91                        return isset( $this->entries[ $key ] ) ? $this->entries[ $key ] : false;
     92                }
     93
     94                /**
     95                 * @param string $singular
     96                 * @param string $context
     97                 * @return string
     98                 */
     99                function translate( $singular, $context = null ) {
     100                        $entry      = new Translation_Entry(
     101                                array(
     102                                        'singular' => $singular,
     103                                        'context'  => $context,
     104                                )
     105                        );
     106                        $translated = $this->translate_entry( $entry );
     107                        return ( $translated && ! empty( $translated->translations ) ) ? $translated->translations[0] : $singular;
     108                }
     109
     110                /**
     111                 * Given the number of items, returns the 0-based index of the plural form to use
     112                 *
     113                 * Here, in the base Translations class, the common logic for English is implemented:
     114                 *  0 if there is one element, 1 otherwise
     115                 *
     116                 * This function should be overridden by the sub-classes. For example MO/PO can derive the logic
     117                 * from their headers.
     118                 *
     119                 * @param integer $count number of items
     120                 */
     121                function select_plural_form( $count ) {
     122                        return 1 == $count ? 0 : 1;
     123                }
     124
     125                /**
     126                 * @return int
     127                 */
     128                function get_plural_forms_count() {
     129                        return 2;
     130                }
     131
     132                /**
     133                 * @param string $singular
     134                 * @param string $plural
     135                 * @param int    $count
     136                 * @param string $context
     137                 */
     138                function translate_plural( $singular, $plural, $count, $context = null ) {
     139                        $entry              = new Translation_Entry(
     140                                array(
     141                                        'singular' => $singular,
     142                                        'plural'   => $plural,
     143                                        'context'  => $context,
     144                                )
     145                        );
     146                        $translated         = $this->translate_entry( $entry );
     147                        $index              = $this->select_plural_form( $count );
     148                        $total_plural_forms = $this->get_plural_forms_count();
     149                        if ( $translated && 0 <= $index && $index < $total_plural_forms &&
     150                                is_array( $translated->translations ) &&
     151                                isset( $translated->translations[ $index ] ) ) {
     152                                return $translated->translations[ $index ];
     153                        } else {
     154                                return 1 == $count ? $singular : $plural;
     155                        }
     156                }
     157
     158                /**
     159                 * Merge $other in the current object.
     160                 *
     161                 * @param Object $other Another Translation object, whose translations will be merged in this one (passed by reference).
     162                 * @return void
     163                 */
     164                function merge_with( &$other ) {
     165                        foreach ( $other->entries as $entry ) {
     166                                $this->entries[ $entry->key() ] = $entry;
     167                        }
     168                }
     169
     170                /**
     171                 * @param object $other
     172                 */
     173                function merge_originals_with( &$other ) {
     174                        foreach ( $other->entries as $entry ) {
     175                                if ( ! isset( $this->entries[ $entry->key() ] ) ) {
     176                                        $this->entries[ $entry->key() ] = $entry;
     177                                } else {
     178                                        $this->entries[ $entry->key() ]->merge_with( $entry );
     179                                }
     180                        }
     181                }
     182        }
     183
     184        class Gettext_Translations extends Translations {
     185                /**
     186                 * The gettext implementation of select_plural_form.
     187                 *
     188                 * It lives in this class, because there are more than one descendand, which will use it and
     189                 * they can't share it effectively.
     190                 *
     191                 * @param int $count
     192                 */
     193                function gettext_select_plural_form( $count ) {
     194                        if ( ! isset( $this->_gettext_select_plural_form ) || is_null( $this->_gettext_select_plural_form ) ) {
     195                                list( $nplurals, $expression )     = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) );
     196                                $this->_nplurals                   = $nplurals;
     197                                $this->_gettext_select_plural_form = $this->make_plural_form_function( $nplurals, $expression );
     198                        }
     199                        return call_user_func( $this->_gettext_select_plural_form, $count );
     200                }
     201
     202                /**
     203                 * @param string $header
     204                 * @return array
     205                 */
     206                function nplurals_and_expression_from_header( $header ) {
     207                        if ( preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches ) ) {
     208                                $nplurals   = (int) $matches[1];
     209                                $expression = trim( $matches[2] );
     210                                return array( $nplurals, $expression );
     211                        } else {
     212                                return array( 2, 'n != 1' );
     213                        }
     214                }
     215
     216                /**
     217                 * Makes a function, which will return the right translation index, according to the
     218                 * plural forms header
     219                 *
     220                 * @param int    $nplurals
     221                 * @param string $expression
     222                 */
     223                function make_plural_form_function( $nplurals, $expression ) {
     224                        try {
     225                                $handler = new Plural_Forms( rtrim( $expression, ';' ) );
     226                                return array( $handler, 'get' );
     227                        } catch ( Exception $e ) {
     228                                // Fall back to default plural-form function.
     229                                return $this->make_plural_form_function( 2, 'n != 1' );
     230                        }
     231                }
     232
     233                /**
     234                 * Adds parentheses to the inner parts of ternary operators in
     235                 * plural expressions, because PHP evaluates ternary oerators from left to right
     236                 *
     237                 * @param string $expression the expression without parentheses
     238                 * @return string the expression with parentheses added
     239                 */
     240                function parenthesize_plural_exression( $expression ) {
     241                        $expression .= ';';
     242                        $res         = '';
     243                        $depth       = 0;
     244                        for ( $i = 0; $i < strlen( $expression ); ++$i ) {
     245                                $char = $expression[ $i ];
     246                                switch ( $char ) {
     247                                        case '?':
     248                                                $res .= ' ? (';
     249                                                $depth++;
     250                                                break;
     251                                        case ':':
     252                                                $res .= ') : (';
     253                                                break;
     254                                        case ';':
     255                                                $res  .= str_repeat( ')', $depth ) . ';';
     256                                                $depth = 0;
     257                                                break;
     258                                        default:
     259                                                $res .= $char;
     260                                }
     261                        }
     262                        return rtrim( $res, ';' );
     263                }
     264
     265                /**
     266                 * @param string $translation
     267                 * @return array
     268                 */
     269                function make_headers( $translation ) {
     270                        $headers = array();
     271                        // sometimes \ns are used instead of real new lines
     272                        $translation = str_replace( '\n', "\n", $translation );
     273                        $lines       = explode( "\n", $translation );
     274                        foreach ( $lines as $line ) {
     275                                $parts = explode( ':', $line, 2 );
     276                                if ( ! isset( $parts[1] ) ) {
     277                                        continue;
     278                                }
     279                                $headers[ trim( $parts[0] ) ] = trim( $parts[1] );
     280                        }
     281                        return $headers;
     282                }
     283
     284                /**
     285                 * @param string $header
     286                 * @param string $value
     287                 */
     288                function set_header( $header, $value ) {
     289                        parent::set_header( $header, $value );
     290                        if ( 'Plural-Forms' == $header ) {
     291                                list( $nplurals, $expression )     = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) );
     292                                $this->_nplurals                   = $nplurals;
     293                                $this->_gettext_select_plural_form = $this->make_plural_form_function( $nplurals, $expression );
     294                        }
     295                }
     296        }
     297endif;
     298
     299if ( ! class_exists( 'NOOP_Translations', false ) ) :
    18300        /**
    19          * Add entry to the PO structure
    20          *
    21          * @param array|Translation_Entry $entry
    22          * @return bool true on success, false if the entry doesn't have a key
     301         * Provides the same interface as Translations, but doesn't do anything
    23302         */
    24         function add_entry($entry) {
    25                 if (is_array($entry)) {
    26                         $entry = new Translation_Entry($entry);
    27                 }
    28                 $key = $entry->key();
    29                 if (false === $key) return false;
    30                 $this->entries[$key] = &$entry;
    31                 return true;
     303        class NOOP_Translations {
     304                var $entries = array();
     305                var $headers = array();
     306
     307                function add_entry( $entry ) {
     308                        return true;
     309                }
     310
     311                /**
     312                 * @param string $header
     313                 * @param string $value
     314                 */
     315                function set_header( $header, $value ) {
     316                }
     317
     318                /**
     319                 * @param array $headers
     320                 */
     321                function set_headers( $headers ) {
     322                }
     323
     324                /**
     325                 * @param string $header
     326                 * @return false
     327                 */
     328                function get_header( $header ) {
     329                        return false;
     330                }
     331
     332                /**
     333                 * @param Translation_Entry $entry
     334                 * @return false
     335                 */
     336                function translate_entry( &$entry ) {
     337                        return false;
     338                }
     339
     340                /**
     341                 * @param string $singular
     342                 * @param string $context
     343                 */
     344                function translate( $singular, $context = null ) {
     345                        return $singular;
     346                }
     347
     348                /**
     349                 * @param int $count
     350                 * @return bool
     351                 */
     352                function select_plural_form( $count ) {
     353                        return 1 == $count ? 0 : 1;
     354                }
     355
     356                /**
     357                 * @return int
     358                 */
     359                function get_plural_forms_count() {
     360                        return 2;
     361                }
     362
     363                /**
     364                 * @param string $singular
     365                 * @param string $plural
     366                 * @param int    $count
     367                 * @param string $context
     368                 */
     369                function translate_plural( $singular, $plural, $count, $context = null ) {
     370                        return 1 == $count ? $singular : $plural;
     371                }
     372
     373                /**
     374                 * @param object $other
     375                 */
     376                function merge_with( &$other ) {
     377                }
    32378        }
    33 
    34         /**
    35          * @param array|Translation_Entry $entry
    36          * @return bool
    37          */
    38         function add_entry_or_merge($entry) {
    39                 if (is_array($entry)) {
    40                         $entry = new Translation_Entry($entry);
    41                 }
    42                 $key = $entry->key();
    43                 if (false === $key) return false;
    44                 if (isset($this->entries[$key]))
    45                         $this->entries[$key]->merge_with($entry);
    46                 else
    47                         $this->entries[$key] = &$entry;
    48                 return true;
    49         }
    50 
    51         /**
    52          * Sets $header PO header to $value
    53          *
    54          * If the header already exists, it will be overwritten
    55          *
    56          * TODO: this should be out of this class, it is gettext specific
    57          *
    58          * @param string $header header name, without trailing :
    59          * @param string $value header value, without trailing \n
    60          */
    61         function set_header($header, $value) {
    62                 $this->headers[$header] = $value;
    63         }
    64 
    65         /**
    66          * @param array $headers
    67          */
    68         function set_headers($headers) {
    69                 foreach($headers as $header => $value) {
    70                         $this->set_header($header, $value);
    71                 }
    72         }
    73 
    74         /**
    75          * @param string $header
    76          */
    77         function get_header($header) {
    78                 return isset($this->headers[$header])? $this->headers[$header] : false;
    79         }
    80 
    81         /**
    82          * @param Translation_Entry $entry
    83          */
    84         function translate_entry(&$entry) {
    85                 $key = $entry->key();
    86                 return isset($this->entries[$key])? $this->entries[$key] : false;
    87         }
    88 
    89         /**
    90          * @param string $singular
    91          * @param string $context
    92          * @return string
    93          */
    94         function translate($singular, $context=null) {
    95                 $entry = new Translation_Entry(array('singular' => $singular, 'context' => $context));
    96                 $translated = $this->translate_entry($entry);
    97                 return ($translated && !empty($translated->translations))? $translated->translations[0] : $singular;
    98         }
    99 
    100         /**
    101          * Given the number of items, returns the 0-based index of the plural form to use
    102          *
    103          * Here, in the base Translations class, the common logic for English is implemented:
    104          *      0 if there is one element, 1 otherwise
    105          *
    106          * This function should be overridden by the sub-classes. For example MO/PO can derive the logic
    107          * from their headers.
    108          *
    109          * @param integer $count number of items
    110          */
    111         function select_plural_form($count) {
    112                 return 1 == $count? 0 : 1;
    113         }
    114 
    115         /**
    116          * @return int
    117          */
    118         function get_plural_forms_count() {
    119                 return 2;
    120         }
    121 
    122         /**
    123          * @param string $singular
    124          * @param string $plural
    125          * @param int    $count
    126          * @param string $context
    127          */
    128         function translate_plural($singular, $plural, $count, $context = null) {
    129                 $entry = new Translation_Entry(array('singular' => $singular, 'plural' => $plural, 'context' => $context));
    130                 $translated = $this->translate_entry($entry);
    131                 $index = $this->select_plural_form($count);
    132                 $total_plural_forms = $this->get_plural_forms_count();
    133                 if ($translated && 0 <= $index && $index < $total_plural_forms &&
    134                                 is_array($translated->translations) &&
    135                                 isset($translated->translations[$index]))
    136                         return $translated->translations[$index];
    137                 else
    138                         return 1 == $count? $singular : $plural;
    139         }
    140 
    141         /**
    142          * Merge $other in the current object.
    143          *
    144          * @param Object $other Another Translation object, whose translations will be merged in this one (passed by reference).
    145          * @return void
    146          **/
    147         function merge_with(&$other) {
    148                 foreach( $other->entries as $entry ) {
    149                         $this->entries[$entry->key()] = $entry;
    150                 }
    151         }
    152 
    153         /**
    154          * @param object $other
    155          */
    156         function merge_originals_with(&$other) {
    157                 foreach( $other->entries as $entry ) {
    158                         if ( !isset( $this->entries[$entry->key()] ) )
    159                                 $this->entries[$entry->key()] = $entry;
    160                         else
    161                                 $this->entries[$entry->key()]->merge_with($entry);
    162                 }
    163         }
    164 }
    165 
    166 class Gettext_Translations extends Translations {
    167         /**
    168          * The gettext implementation of select_plural_form.
    169          *
    170          * It lives in this class, because there are more than one descendand, which will use it and
    171          * they can't share it effectively.
    172          *
    173          * @param int $count
    174          */
    175         function gettext_select_plural_form($count) {
    176                 if (!isset($this->_gettext_select_plural_form) || is_null($this->_gettext_select_plural_form)) {
    177                         list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
    178                         $this->_nplurals = $nplurals;
    179                         $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);
    180                 }
    181                 return call_user_func($this->_gettext_select_plural_form, $count);
    182         }
    183 
    184         /**
    185          * @param string $header
    186          * @return array
    187          */
    188         function nplurals_and_expression_from_header($header) {
    189                 if (preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches)) {
    190                         $nplurals = (int)$matches[1];
    191                         $expression = trim( $matches[2] );
    192                         return array($nplurals, $expression);
    193                 } else {
    194                         return array(2, 'n != 1');
    195                 }
    196         }
    197 
    198         /**
    199          * Makes a function, which will return the right translation index, according to the
    200          * plural forms header
    201          * @param int    $nplurals
    202          * @param string $expression
    203          */
    204         function make_plural_form_function($nplurals, $expression) {
    205                 try {
    206                         $handler = new Plural_Forms( rtrim( $expression, ';' ) );
    207                         return array( $handler, 'get' );
    208                 } catch ( Exception $e ) {
    209                         // Fall back to default plural-form function.
    210                         return $this->make_plural_form_function( 2, 'n != 1' );
    211                 }
    212         }
    213 
    214         /**
    215          * Adds parentheses to the inner parts of ternary operators in
    216          * plural expressions, because PHP evaluates ternary oerators from left to right
    217          *
    218          * @param string $expression the expression without parentheses
    219          * @return string the expression with parentheses added
    220          */
    221         function parenthesize_plural_exression($expression) {
    222                 $expression .= ';';
    223                 $res = '';
    224                 $depth = 0;
    225                 for ($i = 0; $i < strlen($expression); ++$i) {
    226                         $char = $expression[$i];
    227                         switch ($char) {
    228                                 case '?':
    229                                         $res .= ' ? (';
    230                                         $depth++;
    231                                         break;
    232                                 case ':':
    233                                         $res .= ') : (';
    234                                         break;
    235                                 case ';':
    236                                         $res .= str_repeat(')', $depth) . ';';
    237                                         $depth= 0;
    238                                         break;
    239                                 default:
    240                                         $res .= $char;
    241                         }
    242                 }
    243                 return rtrim($res, ';');
    244         }
    245 
    246         /**
    247          * @param string $translation
    248          * @return array
    249          */
    250         function make_headers($translation) {
    251                 $headers = array();
    252                 // sometimes \ns are used instead of real new lines
    253                 $translation = str_replace('\n', "\n", $translation);
    254                 $lines = explode("\n", $translation);
    255                 foreach($lines as $line) {
    256                         $parts = explode(':', $line, 2);
    257                         if (!isset($parts[1])) continue;
    258                         $headers[trim($parts[0])] = trim($parts[1]);
    259                 }
    260                 return $headers;
    261         }
    262 
    263         /**
    264          * @param string $header
    265          * @param string $value
    266          */
    267         function set_header($header, $value) {
    268                 parent::set_header($header, $value);
    269                 if ('Plural-Forms' == $header) {
    270                         list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
    271                         $this->_nplurals = $nplurals;
    272                         $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);
    273                 }
    274         }
    275 }
    276379endif;
    277 
    278 if ( ! class_exists( 'NOOP_Translations', false ) ):
    279 /**
    280  * Provides the same interface as Translations, but doesn't do anything
    281  */
    282 class NOOP_Translations {
    283         var $entries = array();
    284         var $headers = array();
    285 
    286         function add_entry($entry) {
    287                 return true;
    288         }
    289 
    290         /**
    291          *
    292          * @param string $header
    293          * @param string $value
    294          */
    295         function set_header($header, $value) {
    296         }
    297 
    298         /**
    299          *
    300          * @param array $headers
    301          */
    302         function set_headers($headers) {
    303         }
    304 
    305         /**
    306          * @param string $header
    307          * @return false
    308          */
    309         function get_header($header) {
    310                 return false;
    311         }
    312 
    313         /**
    314          * @param Translation_Entry $entry
    315          * @return false
    316          */
    317         function translate_entry(&$entry) {
    318                 return false;
    319         }
    320 
    321         /**
    322          * @param string $singular
    323          * @param string $context
    324          */
    325         function translate($singular, $context=null) {
    326                 return $singular;
    327         }
    328 
    329         /**
    330          *
    331          * @param int $count
    332          * @return bool
    333          */
    334         function select_plural_form($count) {
    335                 return 1 == $count? 0 : 1;
    336         }
    337 
    338         /**
    339          * @return int
    340          */
    341         function get_plural_forms_count() {
    342                 return 2;
    343         }
    344 
    345         /**
    346          * @param string $singular
    347          * @param string $plural
    348          * @param int    $count
    349          * @param string $context
    350          */
    351         function translate_plural($singular, $plural, $count, $context = null) {
    352                         return 1 == $count? $singular : $plural;
    353         }
    354 
    355         /**
    356          * @param object $other
    357          */
    358         function merge_with(&$other) {
    359         }
    360 }
    361 endif;
Note: See TracChangeset for help on using the changeset viewer.