Make WordPress Core


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