WordPress.org

Make WordPress Core

Ticket #26511: 26511.3.diff

File 26511.3.diff, 12.2 KB (added by swissspidy, 21 months ago)
  • new file src/wp-includes/class-wp-locale-switcher.php

    diff --git src/wp-includes/class-wp-locale-switcher.php src/wp-includes/class-wp-locale-switcher.php
    new file mode 100644
    index 0000000..4343733
    - +  
     1<?php
     2/**
     3 * Locale switcher object.
     4 *
     5 * @package WordPress
     6 * @subpackage i18n
     7 * @since 4.7.0
     8 */
     9
     10/**
     11 * Class for switching locales.
     12 *
     13 * @since 4.7.0
     14 */
     15class WP_Locale_Switcher {
     16        /**
     17         * Locale stack.
     18         *
     19         * @since 4.7.0
     20         * @acess private
     21         * @var string[]
     22         */
     23        private $locales = array();
     24
     25        /**
     26         * Original locale.
     27         *
     28         * @since 4.7.0
     29         * @access private
     30         * @var string
     31         */
     32        private $original_locale;
     33
     34        /**
     35         * Translation objects.
     36         *
     37         * @since 4.7.0
     38         * @access private
     39         * @var NOOP_Translations[][]
     40         */
     41        private $translations = array();
     42
     43        /**
     44         * Holds all available languages.
     45         *
     46         * @since 4.7.0
     47         * @access private
     48         * @var array An array of language codes (file names without the .mo extension)
     49         */
     50        private $available_languages = array();
     51
     52        /**
     53         * Constructor.
     54         *
     55         * Stores the original locale.
     56         *
     57         * @since 4.7.0
     58         */
     59        public function __construct() {
     60                $this->original_locale = get_locale();
     61                $this->available_languages = get_available_languages();
     62
     63                add_filter( 'locale', array( $this, 'filter_locale' ) );
     64        }
     65
     66        /**
     67         * Switches the translations according to the given locale.
     68         *
     69         * @since 4.7.0
     70         *
     71         * @global Mo[]      $l10n      An array of available translations.
     72         * @global WP_Locale $wp_locale The WordPress date and time locale object.
     73         *
     74         * @param string $locale The locale to switch to.
     75         * @return bool True on success, false on failure.
     76         */
     77        public function switch_to_locale( $locale ) {
     78                global $l10n;
     79
     80                $current_locale = get_locale();
     81
     82                if ( $locale === $current_locale ) {
     83                        return false;
     84                }
     85
     86                if ( ! in_array( $locale, $this->available_languages ) ) {
     87                        return false;
     88                }
     89
     90                $GLOBALS['wp_locale'] = new WP_Locale();
     91
     92                $this->locales[] = $locale;
     93
     94                if ( ! $l10n ) {
     95                        $l10n = array();
     96                        load_default_textdomain( $locale );
     97                }
     98
     99                if ( empty( $this->translations[ $current_locale ] ) ) {
     100                        foreach ( array_keys( $l10n ) as $textdomain ) {
     101                                $this->translations[ $current_locale ][ $textdomain ] = get_translations_for_domain( $textdomain );
     102                        }
     103                }
     104
     105                if ( ! empty( $this->translations[ $locale ] ) ) {
     106                        foreach ( array_keys( $l10n ) as $textdomain ) {
     107                                if ( isset( $this->translations[ $locale ][ $textdomain ] ) ) {
     108                                        $l10n[ $textdomain ] = $this->translations[ $locale ][ $textdomain ];
     109                                }
     110                        }
     111                } else {
     112                        /* @var MO $mo */
     113                        foreach ( $l10n as $textdomain => $mo ) {
     114                                if ( 'default' === $textdomain ) {
     115                                        load_default_textdomain();
     116
     117                                        continue;
     118                                }
     119
     120                                unload_textdomain( $textdomain );
     121
     122                                if ( $mofile = $mo->get_filename() ) {
     123                                        load_textdomain( $textdomain, $mofile );
     124                                }
     125
     126                                $this->translations[ $locale ][ $textdomain ] = get_translations_for_domain( $textdomain );
     127                        }
     128                }
     129
     130                /**
     131                 * Fires when the locale is switched.
     132                 *
     133                 * @since 4.7.0
     134                 *
     135                 * @param string $locale The new locale.
     136                 */
     137                do_action( 'switch_locale', $locale );
     138
     139                return true;
     140        }
     141
     142        /**
     143         * Restores the translations according to the previous locale.
     144         *
     145         * @since 4.7.0
     146         *
     147         * @global Mo[]      $l10n      An array of available translations.
     148         * @global WP_Locale $wp_locale The WordPress date and time locale object.
     149         *
     150         * @return string|false Locale on success, false on failure.
     151         */
     152        public function restore_previous_locale() {
     153                global $l10n;
     154
     155                $previous_locale = array_pop( $this->locales );
     156
     157                if ( null === $previous_locale ) {
     158                        // The stack is empty, bail.
     159                        return false;
     160                }
     161
     162                if ( null === $l10n ) {
     163                        $l10n = array();
     164                }
     165
     166                $locale = end( $this->locales );
     167
     168                if ( ! $locale ) {
     169                        // There's nothing left in the stack: go back to the original locale.
     170                        $locale = $this->original_locale;
     171                }
     172
     173                foreach ( array_keys( $l10n ) as $textdomain ) {
     174                        if ( isset( $this->translations[ $locale ][ $textdomain ] ) ) {
     175                                $l10n[ $textdomain ] = $this->translations[ $locale ][ $textdomain ];
     176                        }
     177                }
     178
     179                /**
     180                 * Fires when the locale is restored to the previous one.
     181                 *
     182                 * @since 4.7.0
     183                 *
     184                 * @param string $locale The new locale.
     185                 * @param string $previous_locale The previous locale.
     186                 */
     187                do_action( 'restore_previous_locale', $locale, $previous_locale );
     188
     189                $GLOBALS['wp_locale'] = new WP_Locale();
     190
     191                return $locale;
     192        }
     193
     194        /**
     195         * Filters the WordPress install's locale.
     196         *
     197         * @since 4.7.0
     198         *
     199         * @param string $locale The WordPress install's locale.
     200         * @return string The locale currently being switched to.
     201         */
     202        public function filter_locale( $locale ) {
     203                $switched_locale = end( $this->locales );
     204
     205                if ( $switched_locale ) {
     206                        return $switched_locale;
     207                }
     208
     209                return $locale;
     210        }
     211}
  • src/wp-includes/l10n.php

    diff --git src/wp-includes/l10n.php src/wp-includes/l10n.php
    index aaa7611..c0b2a96 100644
    function is_rtl() { 
    11481148                return false;
    11491149        }
    11501150        return $wp_locale->is_rtl();
    1151 }
    1152  No newline at end of file
     1151}
     1152
     1153/**
     1154 * Switches the translations according to the given locale.
     1155 *
     1156 * @since 4.7.0
     1157 *
     1158 * @global WP_Locale_Switcher $wp_locale_switcher
     1159 *
     1160 * @param string $locale The locale.
     1161 * @return bool True on success, false on failure.
     1162 */
     1163function switch_to_locale( $locale ) {
     1164        /* @var WP_Locale_Switcher $wp_locale_switcher */
     1165        global $wp_locale_switcher;
     1166
     1167        return $wp_locale_switcher->switch_to_locale( $locale );
     1168}
     1169
     1170/**
     1171 * Restores the translations according to the previous locale.
     1172 *
     1173 * @since 4.7.0
     1174 *
     1175 * @global WP_Locale_Switcher $wp_locale_switcher
     1176 *
     1177 * @return string|false Locale on success, false on error.
     1178 */
     1179function restore_previous_locale() {
     1180        /* @var WP_Locale_Switcher $wp_locale_switcher */
     1181        global $wp_locale_switcher;
     1182
     1183        return $wp_locale_switcher->restore_previous_locale();
     1184}
  • src/wp-includes/load.php

    diff --git src/wp-includes/load.php src/wp-includes/load.php
    index ae32c7a..6084c00 100644
    function wp_load_translations_early() { 
    868868        require_once ABSPATH . WPINC . '/pomo/mo.php';
    869869        require_once ABSPATH . WPINC . '/l10n.php';
    870870        require_once ABSPATH . WPINC . '/class-wp-locale.php';
     871        require_once ABSPATH . WPINC . '/class-wp-locale-switcher.php';
    871872
    872873        // General libraries
    873874        require_once ABSPATH . WPINC . '/plugin.php';
  • src/wp-includes/pomo/mo.php

    diff --git src/wp-includes/pomo/mo.php src/wp-includes/pomo/mo.php
    index 6bc44d6..47e9b6a 100644
    class MO extends Gettext_Translations { 
    1616        var $_nplurals = 2;
    1717
    1818        /**
     19         * Loaded MO file.
     20         *
     21         * @var string
     22         */
     23        private $filename = '';
     24
     25        /**
     26         * Returns the loaded MO file.
     27         *
     28         * @return string The loaded MO file.
     29         */
     30        public function get_filename() {
     31                return $this->filename;
     32        }
     33
     34        /**
    1935         * Fills up with the entries from MO file $filename
    2036         *
    2137         * @param string $filename MO file to load
    2238         */
    2339        function import_from_file($filename) {
    24                 $reader = new POMO_FileReader($filename);
    25                 if (!$reader->is_resource())
     40                $reader = new POMO_FileReader( $filename );
     41
     42                if ( ! $reader->is_resource() ) {
    2643                        return false;
    27                 return $this->import_from_reader($reader);
     44                }
     45
     46                $this->filename = (string) $filename;
     47
     48                return $this->import_from_reader( $reader );
    2849        }
    2950
    3051        /**
    class MO extends Gettext_Translations { 
    299320                return $this->_nplurals;
    300321        }
    301322}
    302 endif;
    303  No newline at end of file
     323endif;
  • src/wp-settings.php

    diff --git src/wp-settings.php src/wp-settings.php
    index 80f556c..ccf0396 100644
    if ( SHORTINIT ) 
    131131// Load the L10n library.
    132132require_once( ABSPATH . WPINC . '/l10n.php' );
    133133require_once( ABSPATH . WPINC . '/class-wp-locale.php' );
     134require_once( ABSPATH . WPINC . '/class-wp-locale-switcher.php' );
    134135
    135136// Run the installer if WordPress is not installed.
    136137wp_not_installed();
    unset( $locale_file ); 
    384385 */
    385386$GLOBALS['wp_locale'] = new WP_Locale();
    386387
     388/**
     389 * WordPress Locale Switcher object for switching locales.
     390 *
     391 * @since 4.7.0
     392 *
     393 * @global WP_Locale_Switcher $wp_locale_switcher
     394 */
     395$GLOBALS['wp_locale_switcher'] = new WP_Locale_Switcher();
     396
    387397// Load the functions for the active theme, for both parent and child theme if applicable.
    388398if ( ! wp_installing() || 'wp-activate.php' === $pagenow ) {
    389399        if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) )
  • new file tests/phpunit/tests/l10n/localeSwitcher.php

    diff --git tests/phpunit/tests/l10n/localeSwitcher.php tests/phpunit/tests/l10n/localeSwitcher.php
    new file mode 100644
    index 0000000..0416d17
    - +  
     1<?php
     2
     3/**
     4 * @group l10n
     5 * @group i18n
     6 */
     7class Tests_Locale_Switcher extends WP_UnitTestCase {
     8        /**
     9         * @var string
     10         */
     11        protected $locale = '';
     12
     13        /**
     14         * @var string
     15         */
     16        protected $previous_locale = '';
     17
     18        public function setUp() {
     19                $this->locale = '';
     20                $this->previous_locale = '';
     21        }
     22
     23        public function test_switch_to_non_existent_locale_returns_false() {
     24                $this->assertFalse( switch_to_locale( 'de_DE' ) );
     25        }
     26
     27        public function test_switch_to_non_existent_locale_does_not_change_locale() {
     28                switch_to_locale( 'de_DE' );
     29
     30                $this->assertSame( 'en_US', get_locale() );
     31        }
     32
     33        public function test_switch_to_locale_returns_true() {
     34                $expected = switch_to_locale( 'en_GB' );
     35
     36                // Cleanup.
     37                restore_previous_locale();
     38
     39                $this->assertTrue( $expected );
     40        }
     41
     42        public function test_switch_to_locale_changes_the_locale() {
     43                switch_to_locale( 'en_GB' );
     44
     45                $locale = get_locale();
     46
     47                // Cleanup.
     48                restore_previous_locale();
     49
     50                $this->assertSame( 'en_GB', $locale );
     51        }
     52
     53        public function test_switch_to_locale_loads_translation() {
     54                switch_to_locale( 'es_ES' );
     55
     56                $actual = __( 'Invalid parameter.' );
     57
     58                // Cleanup.
     59                restore_previous_locale();
     60
     61                $this->assertSame( 'Parámetro no válido. ', $actual );
     62        }
     63
     64        public function test_switch_to_locale_changes_wp_locale_global() {
     65                global $wp_locale;
     66
     67                switch_to_locale( 'es_ES' );
     68
     69                $wp_locale_es_ES = clone $wp_locale;
     70
     71                // Cleanup.
     72                restore_previous_locale();
     73
     74                $this->markTestIncomplete( 'No es_ES translation available that would change the WP_Locale object.');
     75        }
     76
     77        public function test_switch_to_locale_multiple_times() {
     78                switch_to_locale( 'en_GB' );
     79                switch_to_locale( 'es_ES' );
     80                $locale = get_locale();
     81
     82                // Cleanup.
     83                restore_previous_locale();
     84                restore_previous_locale();
     85
     86                $this->assertSame( 'es_ES', $locale );
     87        }
     88
     89        public function test_restore_locale_without_switching() {
     90                $this->assertFalse( restore_previous_locale() );
     91        }
     92
     93        public function test_restore_locale_changes_the_locale_back() {
     94                switch_to_locale( 'en_GB' );
     95
     96                // Cleanup.
     97                restore_previous_locale();
     98
     99                $this->assertSame( 'en_US', get_locale() );
     100        }
     101
     102        public function test_restore_locale_after_switching_multiple_times() {
     103                switch_to_locale( 'en_GB' );
     104                switch_to_locale( 'es_ES' );
     105                restore_previous_locale();
     106
     107                $locale = get_locale();
     108
     109                // Cleanup.
     110                restore_previous_locale();
     111
     112                $this->assertSame( 'en_GB', $locale );
     113        }
     114
     115        public function test_restore_locale_restores_translation() {
     116                switch_to_locale( 'es_ES' );
     117                restore_previous_locale();
     118
     119                $actual = __( 'Invalid parameter.' );
     120
     121                $this->assertSame( 'Invalid parameter.', $actual );
     122        }
     123
     124        public function test_restore_locale_action_passes_previous_locale() {
     125                switch_to_locale( 'en_GB' );
     126                switch_to_locale( 'es_ES' );
     127
     128                add_action( 'restore_previous_locale', array( $this, 'store_locale' ), 10, 2 );
     129
     130                restore_previous_locale();
     131
     132                $previous_locale = $this->previous_locale;
     133
     134                // Cleanup.
     135                restore_previous_locale();
     136
     137                $this->assertSame( 'es_ES', $previous_locale );
     138        }
     139
     140        public function store_locale( $locale, $previous_locale ) {
     141                $this->locale = $locale;
     142                $this->previous_locale = $previous_locale;
     143        }
     144}
  • tests/phpunit/tests/locale.php

    diff --git tests/phpunit/tests/locale.php tests/phpunit/tests/locale.php
    index 1c335f4..79372d6 100644
     
    11<?php
    22
    33/**
    4  * @group locale
     4 * @group l10n
    55 * @group i18n
    66 */
    77class Tests_Locale extends WP_UnitTestCase {