Make WordPress Core

Ticket #17268: 17268.1.diff

File 17268.1.diff, 28.7 KB (added by Mte90, 7 years ago)

it was missing a require

  • src/wp-includes/l10n.php

     
    581581         */
    582582        $mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain );
    583583
    584         if ( !is_readable( $mofile ) ) return false;
     584        if ( !is_readable( $mofile ) ) return false;
    585585
    586         $mo = new MO();
     586        if ( isset( $l10n[$domain] ) ) {
     587                if ( $l10n[$domain] instanceof MO_dynamic && $l10n[$domain]->Mo_file_loaded( $mofile ) ) {
     588                        return true;
     589                }
     590        }
     591
     592        $use_mo_dynamic = apply_filters( 'load_mo_dynamic', true, $domain );
     593        if( $use_mo_dynamic ) {
     594                $cache_mo_dynamic = apply_filters( 'cache_mo_dynamic', true, $domain );
     595                $mo = new MO_dynamic ( $domain, $cache_mo_dynamic );
     596        } else {
     597                $mo = new MO();
     598        }
     599
    587600        if ( !$mo->import_from_file( $mofile ) ) return false;
    588 
    589         if ( isset( $l10n[$domain] ) )
     601
     602        if ( isset( $l10n[$domain] ) ){
    590603                $mo->merge_with( $l10n[$domain] );
     604                if ( $l10n[$domain] instanceof MO_dynamic ) {
     605                        $l10n[$domain]->unhook_and_close();
     606                }
     607        }
    591608
    592609        unset( $l10n_unloaded[ $domain ] );
    593610
  • src/wp-includes/load.php

     
    870870        require ABSPATH . WPINC . '/version.php';
    871871
    872872        // Translation and localization
     873        require_once ABSPATH . WPINC . '/pomo/native.php' ;
    873874        require_once ABSPATH . WPINC . '/pomo/mo.php';
     875        require_once ABSPATH . WPINC . '/pomo/mo-dynamic-loader.php';
    874876        require_once ABSPATH . WPINC . '/l10n.php';
    875877        require_once ABSPATH . WPINC . '/class-wp-locale.php';
    876878        require_once ABSPATH . WPINC . '/class-wp-locale-switcher.php';
  • src/wp-includes/pomo/mo-dynamic-loader.php

     
     1<?php
     2/**
     3 * Dynamic loading and parsing of MO files
     4 *
     5 * @author Björn Ahrens <bjoern@ahrens.net>
     6 * @package WP Performance Pack
     7 * @since 0.1
     8 */
     9
     10/**
     11 * Class holds information about a single MO file
     12 */
     13class MO_item {
     14        var $reader = NULL;
     15        var $mofile = '';
     16
     17        var $loaded = false;
     18        var $total = 0;
     19        var $originals = array();
     20        var $originals_table;
     21        var $translations_table;
     22        var $last_access;
     23
     24        var $hash_table;
     25        var $hash_length = 0;
     26
     27        function clear_reader () {
     28                if ( $this->reader !== NULL ) {
     29                        $this->reader->close();
     30                        $this->reader = NULL;
     31                }
     32        }
     33}
     34
     35/**
     36 * Class for working with MO files
     37 * Translation entries are created dynamically.
     38 * Due to this export and save functions are not implemented.
     39 */
     40class MO_dynamic extends Gettext_Translations {
     41        private $caching = false;
     42        private $modified = false;
     43
     44        protected $domain = '';
     45        protected $_nplurals = 2;
     46        protected $MOs = array();
     47
     48        protected $translations = NULL;
     49        protected $base_translations = NULL;
     50
     51        function __construct( $domain, $caching = false ) {
     52                $this->domain = $domain;
     53                $this->caching = $caching;
     54                if ( $caching ) {
     55                        add_action ( 'shutdown', array( $this, 'save_to_cache' ) );
     56                        add_action ( 'admin_init', array( $this, 'save_base_translations' ), 100 );
     57                }
     58                // Reader has to be destroyed befor any upgrades or else upgrade might fail, if a
     59                // reader is loaded (cannot delete old plugin/theme/etc. because a language file
     60                // is still opened).
     61                add_filter('upgrader_pre_install', array($this, 'clear_reader_before_upgrade'), 10, 2);
     62        }
     63
     64        static function get_byteorder($magic) {
     65                // The magic is 0x950412de
     66
     67                // bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
     68                $magic_little = (int) - 1794895138;
     69                $magic_little_64 = (int) 2500072158;
     70                // 0xde120495
     71                $magic_big = ((int) - 569244523) & 0xFFFFFFFF;
     72                if ($magic_little == $magic || $magic_little_64 == $magic) {
     73                        return 'little';
     74                } else if ($magic_big == $magic) {
     75                        return 'big';
     76                } else {
     77                        return false;
     78                }
     79        }
     80
     81        function unhook_and_close () {
     82                remove_action ( 'shutdown', array( $this, 'save_to_cache' ) );
     83                remove_action ( 'admin_init', array( $this, 'save_base_translations' ), 100 );
     84                foreach ( $this->MOs as $moitem ) {
     85                        $moitem->clear_reader();
     86                }
     87                $this->MOs = array();
     88        }
     89
     90        function __destruct() {
     91                foreach ( $this->MOs as $moitem ) {
     92                        $moitem->clear_reader();
     93                }
     94        }
     95
     96        function clear_reader_before_upgrade($return, $plugin) {
     97                // stripped down copy of class-wp-upgrader.php Plugin_Upgrader::deactivate_plugin_before_upgrade
     98                if ( is_wp_error($return) ) //Bypass.
     99                        return $return;
     100
     101                foreach ( $this->MOs as $moitem ) {
     102                        $moitem->clear_reader();
     103                }
     104        }
     105
     106        function get_current_url () {
     107                $current_url = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
     108                if ( isset($_SERVER['QUERY_STRING']) && ( $len = strlen( $_SERVER['QUERY_STRING'] ) ) > 0 ) {
     109                        $current_url = substr ( $current_url, 0, strlen($current_url) - $len - 1 );
     110                }
     111                if ( substr( $current_url, -10 ) === '/wp-admin/' ) {
     112                        $current_url .= 'index.php';
     113                }
     114                if ( isset( $_GET['page'] ) ) {
     115                        $current_url .= '?page=' . $_GET['page'];
     116                }
     117                return $current_url;
     118        }
     119
     120        function import_from_file( $filename ) {
     121                $moitem = new MO_item();
     122                $moitem->mofile = $filename;
     123                $this->MOs[] = $moitem;
     124
     125                // because only a reference to the MO file is created, at this point there is no information if $filename is a valid MO file, so the return value is always true
     126                return true;
     127        }
     128
     129        function save_base_translations () {
     130                if ( is_admin() && $this->translations !== NULL && $this->base_translations === NULL ) {
     131                        $this->base_translations = $this->translations;
     132                        $this->translations = array();
     133                }
     134        }
     135
     136        private function cache_get ( $key, $cache_time ) {
     137                $t = wp_cache_get( $key, 'dymoloader1.0' );
     138                if ( $t !== false && isset( $t['data'] ) ) {
     139                        // check soft expire
     140                        if ( $t['softexpire'] < time() ) {
     141                                // update cache with new soft expire time
     142                                $t['softexpire'] = time() + ( $cache_time - ( 5 * MINUTE_IN_SECONDS ) );
     143                                wp_cache_replace( $key, $t, 'dymoloader1.0', $cache_time );
     144                        }
     145                        return json_decode( gzuncompress( $t['data'] ), true );
     146                }
     147                return NULL;
     148        }
     149
     150        private function cache_set ( $key, $cache_time, $data ) {
     151                $t = array();
     152                $t['softexpire'] = time() + ( $cache_time - ( 5 * MINUTE_IN_SECONDS ) );
     153                $t['data'] = gzcompress( json_encode( $data ) );
     154                wp_cache_set( $key, $t, 'dymoloader1.0', $cache_time );
     155        }
     156
     157        function import_domain_from_cache () {
     158                // build cache key from domain and request uri
     159                if ( $this->caching ) {
     160                        if ( is_admin() ) {
     161                                $this->base_translations = $this->cache_get( 'backend_' . $this->domain, HOUR_IN_SECONDS );
     162                                $this->translations = $this->cache_get( 'backend_' . $this->domain . '_' . $this->get_current_url(), 30 * MINUTE_IN_SECONDS );
     163                        } else {
     164                                $this->translations = $this->cache_get( 'frontend_' . $this->domain, HOUR_IN_SECONDS );
     165                        }
     166                }
     167
     168                if ( $this->translations === NULL ) {
     169                        $this->translations = array();
     170                }
     171        }
     172
     173        function save_to_cache () {
     174                if ( $this->modified ) {
     175                        if ( is_admin() ) {
     176                                $this->cache_set( 'backend_' . $this->domain . '_' . $this->get_current_url(), 30 * MINUTE_IN_SECONDS, $this->translations ); // keep admin page cache for 30 minutes
     177                                if ( count( $this->base_translations ) > 0 ) {
     178                                        $this->cache_set( 'backend_'.$this->domain, HOUR_IN_SECONDS, $this->base_translations ); // keep admin base cache for 60 minutes
     179                                }
     180                        } else {
     181                                $this->cache_set( 'frontend_'.$this->domain, HOUR_IN_SECONDS, $this->translations ); // keep front end cache for 60 minutes
     182                        }
     183                }
     184        }
     185
     186        private function import_fail ( &$moitem ) {
     187                $moitem->reader->close();
     188                $moitem->reader = false;
     189                unset( $moitem->originals );
     190                unset( $moitem->originals_table );
     191                unset( $moitem->translations_table );
     192                unset( $moitem->hash_table );
     193
     194                return false;
     195        }
     196
     197        function import_from_reader( &$moitem ) {
     198                if ( $moitem->reader !== NULL) {
     199                        return ( $moitem->reader !== false );
     200                }
     201
     202                $file_size = filesize( $moitem->mofile );
     203                $moitem->reader=new POMO_FileReader( $moitem->mofile );
     204
     205                if ( $moitem->loaded === true ) {
     206                        return true;
     207                }
     208
     209                $endian_string = static::get_byteorder( $moitem->reader->readint32() );
     210                if ( false === $endian_string ) {
     211                        return $this->import_fail( $moitem );
     212                }
     213                $moitem->reader->setEndian( $endian_string );
     214                $endian = ( 'big' == $endian_string ) ? 'N' : 'V';
     215
     216                $header = $moitem->reader->read( 24 );
     217                if ( $moitem->reader->strlen( $header ) != 24 ) {
     218                        return $this->import_fail( $moitem );
     219                }
     220
     221                // parse header
     222                $header = unpack( "{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header );
     223                if ( !is_array( $header ) ) {
     224                        return $this->import_fail( $moitem );
     225                }
     226                extract( $header );
     227
     228                // support revision 0 of MO format specs, only
     229                if ( $revision !== 0 ) {
     230                        return $this->import_fail( $moitem );
     231                }
     232
     233                $moitem->total = $total;
     234
     235                // read hashtable
     236                $moitem->hash_length = $hash_length;
     237                if ( $hash_length > 0 ) {
     238                        $moitem->reader->seekto ( $hash_addr );
     239                        $str = $moitem->reader->read( $hash_length * 4 );
     240                        if ( $moitem->reader->strlen( $str ) != $hash_length * 4 ) {
     241                                return $this->import_fail( $moitem );
     242                        }
     243                        if ( class_exists ( 'SplFixedArray' ) )
     244                                $moitem->hash_table = SplFixedArray::fromArray( unpack ( $endian.$hash_length, $str ), false );
     245                        else
     246                                $moitem->hash_table = array_slice( unpack ( $endian.$hash_length, $str ), 0 ); // force zero based index
     247                }
     248
     249                // read originals' indices
     250                $moitem->reader->seekto( $originals_lenghts_addr );
     251                $originals_lengths_length = $translations_lenghts_addr - $originals_lenghts_addr;
     252                if ( $originals_lengths_length != $total * 8 ) {
     253                        return $this->import_fail( $moitem );
     254                }
     255                $str = $moitem->reader->read( $originals_lengths_length );
     256                if ( $moitem->reader->strlen( $str ) != $originals_lengths_length ) {
     257                        return $this->import_fail( $moitem );
     258                }
     259                if ( class_exists ( 'SplFixedArray' ) )
     260                        $moitem->originals_table = SplFixedArray::fromArray( unpack ( $endian.($total * 2), $str ), false );
     261                else
     262                        $moitem->originals_table = array_slice( unpack ( $endian.($total * 2), $str ), 0 ); // force zero based index
     263
     264                // "sanity check" ( i.e. test for corrupted mo file )
     265                for ( $i = 0, $max = $total * 2; $i < $max; $i+=2 ) {
     266                        if ( $moitem->originals_table[ $i + 1 ] > $file_size
     267                                || $moitem->originals_table[ $i + 1 ] + $moitem->originals_table[ $i ] > $file_size ) {
     268                                return $this->import_fail( $moitem );
     269                        }
     270                }
     271
     272                // read translations' indices
     273                $translations_lenghts_length = $hash_addr - $translations_lenghts_addr;
     274                if ( $translations_lenghts_length != $total * 8 ) {
     275                        return $this->import_fail( $moitem );
     276                }
     277                $str = $moitem->reader->read( $translations_lenghts_length );
     278                if ( $moitem->reader->strlen( $str ) != $translations_lenghts_length ) {
     279                        return $this->import_fail( $moitem );
     280                }
     281                if ( class_exists ( 'SplFixedArray' ) )
     282                        $moitem->translations_table = SplFixedArray::fromArray( unpack ( $endian.($total * 2), $str ), false );
     283                else
     284                        $moitem->translations_table = array_slice( unpack ( $endian.($total * 2), $str ), 0 ); // force zero based index
     285
     286                // "sanity check" ( i.e. test for corrupted mo file )
     287                for ( $i = 0, $max = $total * 2; $i < $max; $i+=2 ) {
     288                        if ( $moitem->translations_table[ $i + 1 ] > $file_size
     289                                || $moitem->translations_table[ $i + 1 ] + $moitem->translations_table[ $i ] > $file_size ) {
     290                                return $this->import_fail( $moitem );
     291                        }
     292                }
     293
     294                $moitem->loaded = true; // read headers can fail, so set loaded to true
     295
     296                // read headers
     297                for ( $i = 0, $max = $total * 2; $i < $max; $i+=2 ) {
     298                        $original = '';
     299                        if ( $moitem->originals_table[$i] > 0 ) {
     300                                $moitem->reader->seekto( $moitem->originals_table[$i+1] );
     301                                $original = $moitem->reader->read( $moitem->originals_table[$i] );
     302
     303                                $j = strpos( $original, 0 );
     304                                if ( $j !== false )
     305                                        $original = substr( $original, 0, $i );
     306                        }
     307
     308                        if ( $original === '' ) {
     309                                $translation = '';
     310                                if ( $moitem->translations_table[$i] > 0 ) {
     311                                        $moitem->reader->seekto( $moitem->translations_table[$i+1] );
     312                                        $translation = $moitem->reader->read( $moitem->translations_table[$i] );
     313                                }
     314
     315                                $this->set_headers( $this->make_headers( $translation ) );
     316                        } else
     317                                return true;
     318                }
     319                return true;
     320        }
     321
     322        protected function search_translation ( $key ) {
     323                $hash_val = NULL;
     324                $key_len = strlen( $key );
     325
     326                for ( $j = 0, $max = count ( $this->MOs ); $j < $max; $j++ ) {
     327                        $moitem = $this->MOs[$j];
     328                        if ( $moitem->reader == NULL ) {
     329                                if ( !$this->import_from_reader( $moitem ) ) {
     330                                        // Error reading MO file, so delete it from MO list to prevent subsequent access
     331                                        unset( $this->MOs[$j] );
     332                                        return false; // return or continue?
     333                                }
     334                        }
     335
     336                        if ($moitem->hash_length>0) {
     337                                /* Use mo file hash table to search translation */
     338
     339                                // calculate hash value
     340                                // hashpjw function by P.J. Weinberger from gettext hash-string.c
     341                                // adapted to php and its quirkiness caused by missing unsigned ints and shift operators...
     342                                if ( $hash_val === NULL) {
     343                                        $hash_val = 0;
     344                                        $chars = unpack ( 'C*', $key ); // faster than accessing every single char by ord(char)
     345                                        foreach ( $chars as $char ) {
     346                                                $hash_val = ( $hash_val << 4 ) + $char;
     347                                                if( 0 !== ( $g = $hash_val & 0xF0000000 ) ){
     348                                                        if ( $g < 0 )
     349                                                                $hash_val ^= ( ( ($g & 0x7FFFFFFF) >> 24 ) | 0x80 ); // wordaround: php operator >> is arithmetic, not logic, so shifting negative values gives unexpected results. Cut sign bit, shift right, set sign bit again.
     350                                                                /*
     351                                                                workaround based on this function (adapted to actual used parameters):
     352
     353                                                                function shr($var,$amt) {
     354                                                                        $mask = 0x40000000;
     355                                                                        if($var < 0) {
     356                                                                                $var &= 0x7FFFFFFF;
     357                                                                                $mask = $mask >> ($amt-1);
     358                                                                                return ($var >> $amt) | $mask;
     359                                                                        }
     360                                                                        return $var >> $amt;
     361                                                                }
     362                                                                */
     363                                                        else
     364                                                                $hash_val ^= ( $g >> 24 );
     365                                                        $hash_val ^= $g;
     366                                                }
     367                                        }
     368                                }
     369
     370                                // calculate hash table index and increment
     371                                if ( $hash_val >= 0 ) {
     372                                        $idx = $hash_val % $moitem->hash_length;
     373                                        $incr = 1 + ($hash_val % ($moitem->hash_length - 2));
     374                                } else {
     375                                        $hash_val = (float) sprintf('%u', $hash_val); // workaround php not knowing unsigned int - %u outputs $hval as unsigned, then cast to float
     376                                        $idx = fmod( $hash_val, $moitem->hash_length);
     377                                        $incr = 1 + fmod ($hash_val, ($moitem->hash_length - 2));
     378                                }
     379
     380                                $orig_idx = $moitem->hash_table[$idx];
     381                                while ( $orig_idx != 0 ) {
     382                                        $orig_idx--; // index adjustment
     383
     384                                        $pos = $orig_idx * 2;
     385                                        if ( $orig_idx < $moitem->total // orig_idx must be in range
     386                                                 && $moitem->originals_table[$pos] >= $key_len ) { // and original length must be equal or greater as key length (original can contain plural forms)
     387
     388                                                // read original string
     389                                                $mo_original = '';
     390                                                if ( $moitem->originals_table[$pos] > 0 ) {
     391                                                        $moitem->reader->seekto( $moitem->originals_table[$pos+1] );
     392                                                        $mo_original = $moitem->reader->read( $moitem->originals_table[$pos] );
     393                                                }
     394
     395                                                if ( $moitem->originals_table[$pos] == $key_len
     396                                                         || ord( $mo_original{$key_len} ) == 0 ) {
     397                                                        // strings can only match if they have the same length, no need to inspect otherwise
     398
     399                                                        if ( false !== ( $i = strpos( $mo_original, 0 ) ) )
     400                                                                $cmpval = strncmp( $key, $mo_original, $i );
     401                                                        else
     402                                                                $cmpval = strcmp( $key, $mo_original );
     403
     404                                                        if ( $cmpval === 0 ) {
     405                                                                // key found, read translation string
     406                                                                $moitem->reader->seekto( $moitem->translations_table[$pos+1] );
     407                                                                $translation = $moitem->reader->read( $moitem->translations_table[$pos] );
     408                                                                if ( $j > 0 ) {
     409                                                                        // Assuming frequent subsequent translations from the same file resort MOs by access time to avoid unnecessary search in the wrong files.
     410                                                                        $moitem->last_access=time();
     411                                                                        usort( $this->MOs, function ($a, $b) {return ($b->last_access - $a->last_access);} );
     412                                                                }
     413                                                                return $translation;
     414                                                        }
     415                                                }
     416                                        }
     417
     418                                        if ($idx >= $moitem->hash_length - $incr)
     419                                                $idx -= ($moitem->hash_length - $incr);
     420                                        else
     421                                                $idx += $incr;
     422                                        $orig_idx = $moitem->hash_table[$idx];
     423                                }
     424                        } else {
     425                                /* No hash-table, do binary search for matching originals entry */
     426                                $left = 0;
     427                                $right = $moitem->total-1;
     428
     429                                while ( $left <= $right ) {
     430                                        $pivot = $left + (int) ( ( $right - $left ) / 2 );
     431                                        $pos = $pivot * 2;
     432
     433                                        if ( isset( $moitem->originals[$pivot] ) ) {
     434                                                $mo_original = $moitem->originals[$pivot];
     435                                        } else {
     436                                                // read and "cache" original string to improve performance of subsequent searches
     437                                                if ( $moitem->originals_table[$pos] > 0 ) {
     438                                                        $moitem->reader->seekto( $moitem->originals_table[$pos+1] );
     439                                                        $mo_original = $moitem->reader->read( $moitem->originals_table[$pos] );
     440                                                } else {
     441                                                        $mo_original = '';
     442                                                }
     443                                                $moitem->originals[$pivot] = $mo_original;
     444                                        }
     445
     446                                        if ( false !== ( $i = strpos( $mo_original, 0 ) ) )
     447                                                $cmpval = strncmp( $key, $mo_original, $i );
     448                                        else
     449                                                $cmpval = strcmp( $key, $mo_original );
     450
     451                                        if ( $cmpval === 0 ) {
     452                                                // key found read translation string
     453                                                $moitem->reader->seekto( $moitem->translations_table[$pos+1] );
     454                                                $translation = $moitem->reader->read( $moitem->translations_table[$pos] );
     455                                                if ( $j > 0 ) {
     456                                                        // Assuming frequent subsequent translations from the same file resort MOs by access time to avoid unnecessary search in the wrong files.
     457                                                        $moitem->last_access=time();
     458                                                        usort( $this->MOs, function ($a, $b) {return ($b->last_access - $a->last_access);} );
     459                                                }
     460                                                return $translation;
     461                                        } else if ( $cmpval < 0 ) {
     462                                                $right = $pivot - 1;
     463                                        } else { // if ($cmpval>0)
     464                                                $left = $pivot + 1;
     465                                        }
     466                                }
     467                        }
     468                }
     469                // key not found
     470                return false;
     471        }
     472
     473        function translate ($singular, $context = NULL) {
     474                if ( !isset ($singular{0} ) ) return $singular;
     475
     476                if ( $context == NULL ) {
     477                        $s = $singular;
     478                } else {
     479                        $s = $context . chr(4) . $singular;
     480                }
     481
     482                if ( $this->translations === NULL ) {
     483                        $this->import_domain_from_cache();
     484                }
     485
     486                if ( isset( $this->translations[$s] ) ) {
     487                        $t = $this->translations[$s];
     488                } elseif ( isset ($this->base_translations[$s] ) ) {
     489                        $t = $this->base_translations[$s];
     490                } else {
     491                        if ( false !== ( $t = $this->search_translation( $s ) ) ) {
     492                                $this->translations[$s] = $t;
     493                                $this->modified = true;
     494                        }
     495                }
     496
     497                if ( $t !== false ) {
     498                        if ( false !== ( $i = strpos( $t, 0 ) ) ) {
     499                                return substr( $t, 0, $i );
     500                        } else {
     501                                return $t;
     502                        }
     503                } else {
     504                        $this->translations[$s] = $singular;
     505                        $this->modified = true;
     506                        return $singular;
     507                }
     508        }
     509
     510        function translate_plural ($singular, $plural, $count, $context = null) {
     511                if ( !isset( $singular{0} ) ) return $singular;
     512
     513                // Get the "default" return-value
     514                $default = ($count == 1 ? $singular : $plural);
     515
     516                if ( $context == NULL ) {
     517                        $s = $singular;
     518                } else {
     519                        $s = $context . chr(4) . $singular;
     520                }
     521
     522                if ( $this->translations === NULL ) {
     523                        $this->import_domain_from_cache();
     524                }
     525
     526                if ( isset( $this->translations[$s] ) ) {
     527                        $t = $this->translations[$s];
     528                } elseif ( isset ($this->base_translations[$s] ) ) {
     529                        $t = $this->base_translations[$s];
     530                } else {
     531                        if ( false !== ( $t = $this->search_translation( $s ) ) ) {
     532                                $this->translations[$s] = $t;
     533                                $this->modified = true;
     534                        }
     535                }
     536
     537                if ( $t !== false ) {
     538                        if ( false !== ( $i = strpos( $t, 0 ) ) ) {
     539                                if ( $count == 1 ) {
     540                                        return substr ( $t, 0, $i );
     541                                } else {
     542                                        // only one plural form is assumed - needs improvement
     543                                        return substr( $t, $i+1 );
     544                                }
     545                        } else {
     546                                return $default;
     547                        }
     548                } else {
     549                        $this->translations[$s] = $singular . chr(0) . $plural;
     550                        $this->modified = true;
     551                        return $default;
     552                }
     553        }
     554
     555        function merge_with( &$other ) {
     556                if ( $other instanceof WPPP_MO_dynamic ) {
     557                        if ( $other->translations !== NULL ) {
     558                                foreach( $other->translations as $key => $translation ) {
     559                                        $this->translations[$key] = $translation;
     560                                }
     561                        }
     562                        if ( $other->base_translations !== NULL ) {
     563                                foreach( $other->base_translations as $key => $translation ) {
     564                                        $this->base_translations[$key] = $translation;
     565                                }
     566                        }
     567
     568                        foreach ( $other->MOs as $moitem ) {
     569                                $i = 0;
     570                                $c = count( $this->MOs );
     571                                $found = false;
     572                                while ( !$found && ( $i < $c ) ) {
     573                                        $found = $this->MOs[$i]->mofile == $moitem->mofile;
     574                                        $i++;
     575                                }
     576                                if ( !$found )
     577                                        $this->MOs[] = $moitem;
     578                        }
     579                }
     580        }
     581
     582        function MO_file_loaded ( $mofile ) {
     583                foreach ($this->MOs as $moitem) {
     584                        if ($moitem->mofile == $mofile) {
     585                                return true;
     586                        }
     587                }
     588                return false;
     589        }
     590}
     591 No newline at end of file
  • src/wp-includes/pomo/native.php

     
     1<?PHP
     2
     3  /**
     4   * Native GetText-Support for WordPress
     5   * ------------------------------------
     6   *
     7   * Copyright (C) 2012 Bernd Holzmueller <bernd@quarxconnect.de>
     8   *
     9   * This program is free software: you can redistribute it and/or modify
     10   * it under the terms of the GNU General Public License as published by
     11   * the Free Software Foundation, either version 3 of the License, or
     12   * (at your option) any later version.
     13   *
     14   * This program is distributed in the hope that it will be useful,
     15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17   * GNU General Public License for more details.
     18   *
     19   * You should have received a copy of the GNU General Public License
     20   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     21   *
     22   * @revision 02
     23   * @author Bernd Holzmueller <bernd@tiggerswelt.net>
     24   * @url http://oss.tiggerswelt.net/wordpress/3.3.1/
     25   **/
     26
     27  // Check if gettext-support is available
     28  if (!extension_loaded ('gettext'))
     29    return;
     30
     31  class Translate_GetText_Native {
     32    // Our default domain
     33    private $Domain = null;
     34
     35    // Merged domains
     36    private $pOthers = array ();
     37    private $sOthers = array ();
     38
     39    // Some Dummy-Function just to be API-compatible
     40    function add_entry ($entry) { return false; }
     41    function add_entry_or_merge ($entry) { return false; }
     42    function set_header ($header, $value) { return false; }
     43    function set_headers (&$headers) { return false; }
     44    function get_header ($header) { return false; }
     45    function translate_entry (&$entry) { return false; }
     46
     47    // {{{ select_plural_form
     48    /**
     49     * Given the number of items, returns the 0-based index of the plural form to use
     50     *
     51     * Here, in the base Translations class, the common logic for English is implemented:
     52     *      0 if there is one element, 1 otherwise
     53     *
     54     * This function should be overrided by the sub-classes. For example MO/PO can derive the logic
     55     * from their headers.
     56     *
     57     * @param integer $count number of items
     58     **/
     59    function select_plural_form ($count) {
     60      return (1 == $count? 0 : 1);
     61    }
     62    // }}}
     63
     64    function get_plural_forms_count () { return 2; }
     65
     66    // {{{ merge_with
     67    /**
     68     * Merge this translation with another one, the other one takes precedence
     69     *
     70     * @param object $other
     71     *
     72     * @access public
     73     * @return void
     74     **/
     75    function merge_with (&$other) {
     76      $this->pOthers [] = $other;
     77    }
     78    // }}}
     79
     80    // {{{ merge_originals_with
     81    /**
     82     * Merge this translation with another one, this one takes precedence
     83     *
     84     * @param object $other
     85     *
     86     * @access public
     87     * @return void
     88     **/
     89    function merge_originals_with (&$other) {
     90      $this->sOthers [] = $Other;
     91   }
     92    // }}}
     93
     94    // {{{ translate
     95    /**
     96     * Try to translate a given string
     97     *
     98     * @param string $singular
     99     * @param string $context (optional)
     100     *
     101     * @access public
     102     * @return string
     103     **/
     104    function translate ($singular, $context = null) {
     105      // Check for an empty string
     106      if (strlen ($singular) == 0)
     107        return $singular;
     108
     109      // Check other domains that take precedence
     110      foreach ($this->pOthers as $o)
     111        if (($t = $o->translate ($singular, $context)) != $singular)
     112          return $t;
     113
     114      // Make sure we have a domain assigned
     115      if ($this->Domain === null)
     116        return $singular;
     117
     118      // Translate without a context
     119      if ($context === null) {
     120        if (($t = dgettext ($this->Domain, $singular)) != $singular)
     121          return $t;
     122
     123      // Translate with a given context
     124      } else {
     125        $T = $context . "\x04" . $singular;
     126        $t = dgettext ($this->Domain, $T);
     127
     128        if ($T != $t)
     129          return $t;
     130      }
     131
     132      // Check for other domains
     133      foreach ($this->sOthers as $o)
     134        if (($t = $o->translate ($singular, $context)) != $singular)
     135          return $t;
     136
     137      return $singular;
     138    }
     139    // }}}
     140
     141    // {{{ translate_plural
     142    /**
     143     * Try to translate a plural string
     144     *
     145     * @param string $singular Singular version
     146     * @param string $plural Plural version
     147     * @param int $count Number of "items"
     148     * @param string $context (optional)
     149     *
     150     * @access public
     151     * @return string
     152     **/
     153    function translate_plural ($singular, $plural, $count, $context = null) {
     154      // Check for an empty string
     155      if (strlen ($singular) == 0)
     156        return $singular;
     157
     158      // Get the "default" return-value
     159      $default = ($count == 1 ? $singular : $plural);
     160
     161      // Check other domains that take precedence
     162      foreach ($this->pOthers as $o)
     163        if (($t = $o->translate_plural ($singular, $plural, $count, $context)) != $default)
     164          return $t;
     165
     166      // Make sure we have a domain assigned
     167      if ($this->Domain === null)
     168        return $default;
     169
     170      // Translate without context
     171      if ($context === null) {
     172        $t = dngettext ($this->Domain, $singular, $plural, $count);
     173
     174        if (($t != $singular) && ($t != $plural))
     175          return $t;
     176
     177      // Translate using a given context
     178      } else {
     179        $T = $context . "\x04" . $singular;
     180        $t = dngettext ($this->Domain, $T, $plural, $count);
     181
     182        if (($T != $t) && ($t != $plural))
     183          return $t;
     184      }
     185
     186      // Check other domains
     187      foreach ($this->sOthers as $o)
     188        if (($t = $o->translate_plural ($singular, $plural, $count, $context)) != $default)
     189          return $t;
     190
     191      return $default;
     192    }
     193    // }}}
     194
     195    // {{{ import_from_file
     196    /**
     197     * Fills up with the entries from MO file $filename
     198     *
     199     * @param string $filename MO file to load
     200     **/
     201    function import_from_file ($filename) {
     202      // Make sure that the locale is set correctly in environment
     203      global $locale;
     204
     205      putenv ('LC_ALL=' . $locale);
     206      setlocale (LC_ALL, $locale);
     207
     208      // Retrive MD5-hash of the file
     209      # DIRTY! But there is no other way at the moment to make this work
     210      if (!($Domain = md5_file ($filename)))
     211        return false;
     212
     213      // Make sure that the language-directory exists
     214      $Path = './wp-lang/' . $locale . '/LC_MESSAGES';
     215
     216      if (!wp_mkdir_p ($Path))
     217        return false;
     218
     219      // Make sure that the MO-File is existant at the destination
     220      $fn = $Path . '/' . $Domain . '.mo';
     221
     222      if (!is_file ($fn) && !@copy ($filename, $fn))
     223        return false;
     224
     225      // Setup the "domain" for gettext
     226      bindtextdomain ($Domain, './wp-lang/');
     227      bind_textdomain_codeset ($Domain, 'UTF-8');
     228
     229      // Do the final stuff and return success
     230      $this->Domain = $Domain;
     231
     232      return true;
     233    }
     234    // }}}
     235  }
     236
     237  if (function_exists ('class_alias'))
     238    class_alias ('Translate_GetText_Native', 'MO');
     239  else {
     240    class MO extends Translate_GetText_Native { }
     241  }
     242
  • src/wp-settings.php

     
    9999require( ABSPATH . WPINC . '/class-wp-matchesmapregex.php' );
    100100require( ABSPATH . WPINC . '/class-wp.php' );
    101101require( ABSPATH . WPINC . '/class-wp-error.php' );
     102require( ABSPATH . WPINC . '/pomo/native.php' );
    102103require( ABSPATH . WPINC . '/pomo/mo.php' );
     104require( ABSPATH . WPINC . '/pomo/mo-dynamic-loader.php' );
    103105
    104106// Include the wpdb class and, if present, a db.php database drop-in.
    105107global $wpdb;