Make WordPress Core

Changeset 38961


Ignore:
Timestamp:
10/26/2016 03:35:58 PM (10 years ago)
Author:
ocean90
Message:

I18N: Introduce a locale-switching function.

With the introduction of user-specific languages in [38705] it's necessary to be able to switch translations on the fly. For example emails should be sent in the language of the recipient and not the one of the current user.

This introduces a new WP_Locale_Switcher class which is used for switching locales and translations. It holds the stack of locales whenever switch_to_locale( $locale ) is called. With restore_previous_locale() you can restore the previous locale. restore_current_locale() empties the stack and sets the locale back to the initial value.

switch_to_locale() is added to most of core's email functions, either with the value of get_locale() (site language) or get_user_locale() (user language with fallback to site language).

Props yoavf, tfrommen, swissspidy, pbearne, ocean90.
See #29783.
Fixes #26511.

Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/ms.php

    r38876 r38961  
    273273        update_option( 'adminhash', $new_admin_email );
    274274
     275        $switched_locale = switch_to_locale( get_user_locale() );
     276
    275277        /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
    276278        $email_text = __( 'Howdy ###USERNAME###,
     
    316318
    317319        wp_mail( $value, sprintf( __( '[%s] New Admin Email Address' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), $content );
     320
     321        if ( $switched_locale ) {
     322                restore_previous_locale();
     323        }
    318324}
    319325
     
    353359                );
    354360                update_user_meta( $current_user->ID, '_new_email', $new_user_email );
     361
     362                $switched_locale = switch_to_locale( get_user_locale() );
    355363
    356364                /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
     
    396404                wp_mail( $_POST['email'], sprintf( __( '[%s] New Email Address' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), $content );
    397405                $_POST['email'] = $current_user->user_email;
     406
     407                if ( $switched_locale ) {
     408                        restore_previous_locale();
     409                }
    398410        }
    399411}
  • trunk/src/wp-admin/ms-delete-site.php

    r38822 r38961  
    4343        $url_delete = esc_url( admin_url( 'ms-delete-site.php?h=' . $hash ) );
    4444
     45        $switched_locale = switch_to_locale( get_locale() );
     46
    4547        /* translators: Do not translate USERNAME, URL_DELETE, SITE_NAME: those are placeholders. */
    4648        $content = __( "Howdy ###USERNAME###,
     
    7476
    7577        wp_mail( get_option( 'admin_email' ), "[ " . wp_specialchars_decode( get_option( 'blogname' ) ) . " ] ".__( 'Delete My Site' ), $content );
     78
     79        if ( $switched_locale ) {
     80                restore_previous_locale();
     81        }
    7682        ?>
    7783
  • trunk/src/wp-admin/user-new.php

    r38723 r38961  
    8888                        do_action( 'invite_user', $user_id, $role, $newuser_key );
    8989
     90                        $switched_locale = switch_to_locale( get_user_locale( $user_details ) );
     91
    9092                        /* translators: 1: Site name, 2: site URL, 3: role, 4: activation URL */
    9193                        $message = __( 'Hi,
     
    9799%4$s' );
    98100                        wp_mail( $new_user_email, sprintf( __( '[%s] Joining confirmation' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), sprintf( $message, get_option( 'blogname' ), home_url(), wp_specialchars_decode( translate_user_role( $role['name'] ) ), home_url( "/newbloguser/$newuser_key/" ) ) );
     101
     102                        if ( $switched_locale ) {
     103                                restore_previous_locale();
     104                        }
     105
    99106                        $redirect = add_query_arg( array('update' => 'add'), 'user-new.php' );
    100107                }
  • trunk/src/wp-includes/default-filters.php

    r38925 r38961  
    407407add_action( 'before_delete_post', '_reset_front_page_settings_for_post' );
    408408add_action( 'wp_trash_post',      '_reset_front_page_settings_for_post' );
     409add_action( 'change_locale', 'create_initial_post_types' );
    409410
    410411// Post Formats
     
    432433// Taxonomy
    433434add_action( 'init', 'create_initial_taxonomies', 0 ); // highest priority
     435add_action( 'change_locale', 'create_initial_taxonomies' );
    434436
    435437// Canonical
  • trunk/src/wp-includes/l10n.php

    r38955 r38961  
    11791179        return $wp_locale->is_rtl();
    11801180}
     1181
     1182/**
     1183 * Switches the translations according to the given locale.
     1184 *
     1185 * @since 4.7.0
     1186 *
     1187 * @global WP_Locale_Switcher $wp_locale_switcher
     1188 *
     1189 * @param string $locale The locale.
     1190 * @return bool True on success, false on failure.
     1191 */
     1192function switch_to_locale( $locale ) {
     1193        /* @var WP_Locale_Switcher $wp_locale_switcher */
     1194        global $wp_locale_switcher;
     1195
     1196        return $wp_locale_switcher->switch_to_locale( $locale );
     1197}
     1198
     1199/**
     1200 * Restores the translations according to the previous locale.
     1201 *
     1202 * @since 4.7.0
     1203 *
     1204 * @global WP_Locale_Switcher $wp_locale_switcher
     1205 *
     1206 * @return string|false Locale on success, false on error.
     1207 */
     1208function restore_previous_locale() {
     1209        /* @var WP_Locale_Switcher $wp_locale_switcher */
     1210        global $wp_locale_switcher;
     1211
     1212        return $wp_locale_switcher->restore_previous_locale();
     1213}
     1214
     1215/**
     1216 * Restores the translations according to the original locale.
     1217 *
     1218 * @since 4.7.0
     1219 *
     1220 * @global WP_Locale_Switcher $wp_locale_switcher
     1221 *
     1222 * @return string|false Locale on success, false on error.
     1223 */
     1224function restore_current_locale() {
     1225        /* @var WP_Locale_Switcher $wp_locale_switcher */
     1226        global $wp_locale_switcher;
     1227
     1228        return $wp_locale_switcher->restore_current_locale();
     1229}
     1230
     1231/**
     1232 * Whether switch_to_locale() is in effect.
     1233 *
     1234 * @since 4.7.0
     1235 *
     1236 * @global WP_Locale_Switcher $wp_locale_switcher
     1237 *
     1238 * @return bool True if the locale has been switched, false otherwise.
     1239 */
     1240function is_locale_switched() {
     1241        /* @var WP_Locale_Switcher $wp_locale_switcher */
     1242        global $wp_locale_switcher;
     1243
     1244        return $wp_locale_switcher->is_switched();
     1245}
  • trunk/src/wp-includes/load.php

    r38899 r38961  
    842842 * @access private
    843843 *
    844  * @global string    $text_direction
    845  * @global WP_Locale $wp_locale      The WordPress date and time locale object.
     844 * @global string             $text_direction
     845 * @global WP_Locale          $wp_locale      The WordPress date and time locale object.
     846 * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
    846847 *
    847848 * @staticvar bool $loaded
    848849 */
    849850function wp_load_translations_early() {
    850         global $text_direction, $wp_locale;
     851        global $text_direction, $wp_locale, $wp_locale_switcher;
    851852
    852853        static $loaded = false;
     
    865866        require_once ABSPATH . WPINC . '/l10n.php';
    866867        require_once ABSPATH . WPINC . '/class-wp-locale.php';
     868        require_once ABSPATH . WPINC . '/class-wp-locale-switcher.php';
    867869
    868870        // General libraries
     
    916918
    917919        $wp_locale = new WP_Locale();
     920        $wp_locale_switcher = new WP_Locale_Switcher();
     921        $wp_locale_switcher->init();
    918922}
    919923
  • trunk/src/wp-includes/ms-functions.php

    r38943 r38961  
    801801        $from_name = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
    802802        $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
     803
     804        $user = get_user_by( 'login', $user );
     805        $switched_locale = switch_to_locale( get_user_locale( $user ) );
     806
    803807        $message = sprintf(
    804808                /**
     
    850854        );
    851855        wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
     856
     857        if ( $switched_locale ) {
     858                restore_previous_locale();
     859        }
     860
    852861        return true;
    853862}
     
    887896        if ( ! apply_filters( 'wpmu_signup_user_notification', $user, $user_email, $key, $meta ) )
    888897                return false;
     898
     899        $user = get_user_by( 'login', $user );
     900        $switched_locale = switch_to_locale( get_user_locale( $user ) );
    889901
    890902        // Send email with activation link.
     
    935947        );
    936948        wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
     949
     950        if ( $switched_locale ) {
     951                restore_previous_locale();
     952        }
     953
    937954        return true;
    938955}
     
    14491466                return false;
    14501467
     1468        $user = get_userdata( $user_id );
     1469
     1470        $switched_locale = switch_to_locale( get_user_locale( $user ) );
     1471
    14511472        $welcome_email = get_site_option( 'welcome_email' );
    14521473        if ( $welcome_email == false ) {
     
    14691490
    14701491        $url = get_blogaddress_by_id($blog_id);
    1471         $user = get_userdata( $user_id );
    14721492
    14731493        $welcome_email = str_replace( 'SITE_NAME', $current_network->site_name, $welcome_email );
     
    15131533        $subject = apply_filters( 'update_welcome_subject', sprintf( __( 'New %1$s Site: %2$s' ), $current_network->site_name, wp_unslash( $title ) ) );
    15141534        wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
     1535
     1536        if ( $switched_locale ) {
     1537                restore_previous_locale();
     1538        }
     1539
    15151540        return true;
    15161541}
     
    15511576
    15521577        $user = get_userdata( $user_id );
     1578
     1579        $switched_locale = switch_to_locale( get_user_locale( $user ) );
    15531580
    15541581        /**
     
    15911618        $subject = apply_filters( 'update_welcome_user_subject', sprintf( __( 'New %1$s User: %2$s' ), $current_network->site_name, $user->user_login) );
    15921619        wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
     1620
     1621        if ( $switched_locale ) {
     1622                restore_previous_locale();
     1623        }
     1624
    15931625        return true;
    15941626}
  • trunk/src/wp-includes/pluggable.php

    r38470 r38961  
    212212        if ( ! ( $phpmailer instanceof PHPMailer ) ) {
    213213                require_once ABSPATH . WPINC . '/class-phpmailer.php';
    214                 require_once ABSPATH . WPINC . '/class-smtp.php'; 
     214                require_once ABSPATH . WPINC . '/class-smtp.php';
    215215                $phpmailer = new PHPMailer( true );
    216216        }
     
    14181418                $emails = array_flip( $emails );
    14191419        }
     1420
     1421        $switched_locale = switch_to_locale( get_locale() );
    14201422
    14211423        $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
     
    15231525        }
    15241526
     1527        if ( $switched_locale ) {
     1528                restore_previous_locale();
     1529        }
     1530
    15251531        return true;
    15261532}
     
    15691575                        $emails[] = $user->user_email;
    15701576        }
     1577
     1578        $switched_locale = switch_to_locale( get_locale() );
    15711579
    15721580        $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
     
    16651673        }
    16661674
     1675        if ( $switched_locale ) {
     1676                restore_previous_locale();
     1677        }
     1678
    16671679        return true;
    16681680}
     
    17241736
    17251737        if ( 'user' !== $notify ) {
     1738                $switched_locale = switch_to_locale( get_locale() );
    17261739                $message  = sprintf( __( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
    17271740                $message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
     
    17291742
    17301743                @wp_mail( get_option( 'admin_email' ), sprintf( __( '[%s] New User Registration' ), $blogname ), $message );
     1744
     1745                if ( $switched_locale ) {
     1746                        restore_previous_locale();
     1747                }
    17311748        }
    17321749
     
    17491766        $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
    17501767
     1768        $switched_locale = switch_to_locale( get_user_locale( $user ) );
     1769
    17511770        $message = sprintf(__('Username: %s'), $user->user_login) . "\r\n\r\n";
    17521771        $message .= __('To set your password, visit the following address:') . "\r\n\r\n";
     
    17561775
    17571776        wp_mail($user->user_email, sprintf(__('[%s] Your username and password info'), $blogname), $message);
     1777
     1778        if ( $switched_locale ) {
     1779                restore_previous_locale();
     1780        }
    17581781}
    17591782endif;
  • trunk/src/wp-includes/pomo/mo.php

    r35714 r38961  
    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         *
     
    2238         */
    2339        function import_from_file($filename) {
    24                 $reader = new POMO_FileReader($filename);
    25                 if (!$reader->is_resource())
    26                         return false;
    27                 return $this->import_from_reader($reader);
     40                $reader = new POMO_FileReader( $filename );
     41
     42                if ( ! $reader->is_resource() ) {
     43                        return false;
     44                }
     45
     46                $this->filename = (string) $filename;
     47
     48                return $this->import_from_reader( $reader );
    2849        }
    2950
  • trunk/src/wp-includes/user.php

    r38905 r38961  
    18021802                $blog_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
    18031803
     1804                $switched_locale = false;
     1805                if ( ! empty( $send_password_change_email ) || ! empty( $send_email_change_email ) ) {
     1806                        $switched_locale = switch_to_locale( get_user_locale( $user_id ) );
     1807                }
     1808
    18041809                if ( ! empty( $send_password_change_email ) ) {
    1805 
    18061810                        /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
    18071811                        $pass_change_text = __( 'Hi ###USERNAME###,
     
    19111915                        wp_mail( $email_change_email['to'], sprintf( $email_change_email['subject'], $blog_name ), $email_change_email['message'], $email_change_email['headers'] );
    19121916                }
     1917
     1918                if ( $switched_locale ) {
     1919                        restore_previous_locale();
     1920                }
    19131921        }
    19141922
  • trunk/src/wp-settings.php

    r38928 r38961  
    131131require_once( ABSPATH . WPINC . '/l10n.php' );
    132132require_once( ABSPATH . WPINC . '/class-wp-locale.php' );
     133require_once( ABSPATH . WPINC . '/class-wp-locale-switcher.php' );
    133134
    134135// Run the installer if WordPress is not installed.
     
    401402$GLOBALS['wp_locale'] = new WP_Locale();
    402403
     404/**
     405 *  WordPress Locale Switcher object for switching locales.
     406 *
     407 * @since 4.7.0
     408 *
     409 * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
     410 */
     411$GLOBALS['wp_locale_switcher'] = new WP_Locale_Switcher();
     412$GLOBALS['wp_locale_switcher']->init();
     413
    403414// Load the functions for the active theme, for both parent and child theme if applicable.
    404415if ( ! wp_installing() || 'wp-activate.php' === $pagenow ) {
  • trunk/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php

    r37855 r38961  
    1010        private $theme_root;
    1111
    12         function setUp() {
     12        public function setUp() {
    1313                parent::setUp();
    1414
     
    2323                wp_clean_themes_cache();
    2424                unset( $GLOBALS['wp_themes'] );
    25 
     25                unset( $GLOBALS['l10n'] );
    2626                unset( $GLOBALS['l10n_unloaded'] );
    2727        }
    2828
    29         function tearDown() {
     29        public function tearDown() {
    3030                $GLOBALS['wp_theme_directories'] = $this->orig_theme_dir;
    3131                remove_filter( 'theme_root', array( $this, 'filter_theme_root' ) );
     
    3434                wp_clean_themes_cache();
    3535                unset( $GLOBALS['wp_themes'] );
     36                unset( $GLOBALS['l10n'] );
     37                unset( $GLOBALS['l10n_unloaded'] );
    3638
    3739                parent::tearDown();
     
    6163                $is_textdomain_loaded_after  = is_textdomain_loaded( 'internationalized-plugin' );
    6264
    63                 unload_textdomain( 'internationalized-plugin' );
    6465                remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
    6566
     
    8384                $is_textdomain_loaded_after  = is_textdomain_loaded( 'internationalized-theme' );
    8485
    85                 unload_textdomain( 'internationalized-theme' );
    8686                remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
    8787
     
    142142                $this->assertTrue( $is_textdomain_loaded_final );
    143143        }
     144
     145        /**
     146         * @ticket 26511
     147         */
     148        public function test_plugin_translation_after_switching_locale() {
     149                require_once DIR_TESTDATA . '/plugins/internationalized-plugin.php';
     150
     151                switch_to_locale( 'de_DE' );
     152                $expected = i18n_plugin_test();
     153                restore_previous_locale();
     154
     155                $this->assertSame( 'Das ist ein Dummy Plugin', $expected );
     156        }
     157
     158        /**
     159         * @ticket 26511
     160         */
     161        public function test_theme_translation_after_switching_locale() {
     162                switch_theme( 'internationalized-theme' );
     163
     164                require_once get_stylesheet_directory() . '/functions.php';
     165
     166                switch_to_locale( 'de_DE' );
     167                $expected = i18n_theme_test();
     168                restore_previous_locale();
     169
     170                switch_theme( WP_DEFAULT_THEME );
     171
     172                $this->assertSame( 'Das ist ein Dummy Theme', $expected );
     173        }
    144174}
  • trunk/tests/phpunit/tests/locale.php

    r36292 r38961  
    22
    33/**
    4  * @group locale
     4 * @group l10n
    55 * @group i18n
    66 */
Note: See TracChangeset for help on using the changeset viewer.