Make WordPress Core

Opened 6 years ago

Last modified 5 years ago

#44844 new defect (bug)

switch_to_locale does not handle plugins/themes properly in multisite

Reported by: pcfreak30's profile pcfreak30 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 4.9.8
Component: I18N Keywords:
Focuses: Cc:

Description

Running the following test script should enable switching of languages in a multisite.

require_once( dirname( __FILE__ ) . '/wp-load.php' );

switch_to_blog(2);
switch_to_locale('sv_SE');
var_dump(__('my text','my-domain'));

However do to complexities I am not familiar with in unload_textdomain and get_translations_for_domain it does not work. Breaking it down unload_textdomain flags it as unloaded which _load_textdomain_just_in_time via get_translations_for_domain checks and aborts. the only way I have been able to do this is via some hacky filtering and mangling language globals.

Example:

switch_to_blog( $object['blog_id'] );
                        unset( $GLOBALS['locale'] );
                        $locale = get_locale();
                        unset( $GLOBALS['locale'] );
                        restore_current_blog();
                        add_filter( 'locale', [ $this, 'one_time_false' ] );
                        add_filter( 'override_unload_textdomain', [ $this, 'unload_textdomain' ], 10, 2 );

                        switch_to_locale( $locale );
                        remove_filter( 'locale', [ $this, 'one_time_false' ] );
                        remove_filter( 'override_unload_textdomain', [ $this, 'unload_textdomain' ] );
                        switch_to_blog( $object['blog_id'] );

$this->unload_textdomain being:

<?php
public function unload_textdomain( $value, $domain ) {
                if ( isset( $GLOBALS['l10n'][ $domain ] ) ) {
                        unset( $GLOBALS['l10n'][ $domain ] );
                }

                return $value;
        }

and $this->one_time_false being:

<?php
public function one_time_false() {
                remove_filter( 'locale', [ $this, 'one_time_false' ] );

                return false;
        }

Not sure how this should be refactored but this so far should really be unnecessary to do.

Thanks.

Change History (2)

#1 @pcfreak30
6 years ago

After further troubleshooting I have made this test script as the original test code posted was flawed.

<?php
require_once( dirname( __FILE__ ) . '/wp-load.php' );

function test_unload_textdomain( $domain ) {
        if ( isset( $GLOBALS['l10n'][ $domain ] ) ) {
                unset( $GLOBALS['l10n'][ $domain ] );
                unset( $GLOBALS['l10n_unloaded'][ $domain ] );

        }
}

function one_time_false() {
        remove_filter( 'locale',  'one_time_false' );

        return false;
}

add_action( 'unload_textdomain', 'test_unload_textdomain' );
add_filter( 'locale', 'one_time_false' );
switch_to_blog( 3 );
switch_to_locale( 'fi' );
$GLOBALS['wp_rewrite']->init();
do_action( 'init');
var_dump( __( 'some label', 'my-domain' ), get_term_link( 123 ) );

It covers the following what I consider bugs.

  • Does not switch the locale
  • Does not rebuild all post types/taxonomies
  • Does not re-init wp_rewrite to have the right settings for the current subsite

My use case has been in Multisite different subsites may have had different rewrite settings and some post type slugs were translated. This has made up a combination of very hard edge cases to track down.

As of now it seems without this you can only make background requests to each subsite or force cron to only process items that have a blog id of what the current blog is.

#2 @drzraf
5 years ago

Probably not related to multisite. See bug #39210

Note: See TracTickets for help on using tickets.