Make WordPress Core

Changeset 38961


Ignore:
Timestamp:
10/26/2016 03:35:58 PM (7 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.