WordPress.org

Make WordPress Core

Changeset 38961


Ignore:
Timestamp:
10/26/16 15:35:58 (14 months 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.