Make WordPress Core

Opened 3 years ago

Last modified 13 days ago

#26511 reviewing feature request

Introduce a locale-switching function

Reported by: johnbillion Owned by: ocean90
Milestone: Future Release Priority: normal
Severity: normal Version:
Component: I18N Keywords: has-patch dev-feedback has-unit-tests
Focuses: Cc:


When a site's content is displayed in a language that's different to that used in the admin area [1] by using the locale filter in get_locale(), the admin toolbar is shown in the language of the content, not the language of the admin area.

For example, if your content is in French (using fr_FR in the locale filter) but your admin area is in English (using en_US in the locale filter) then the admin toolbar on the front end will display in French rather than English.

The value of get_locale() is used when the translation files are loaded at the beginning of the page load, but there's no easy way to subsequently switch locale and load a different set of translation files later in the page load (ie. when we output the admin toolbar in the footer).

We should introduce a means of changing the locale at any point during the page load and automatically loading in the relevant translation files, overriding existing ones. This could then be used to switch the language before admin-related output on the front end (primarily the admin toolbar, but potentially any admin-related item).

Leaving this as a feature request for now because I don't have a solution in mind.

[1] Several plugins support this, such as WPML, Babble and Admin in English.

Attachments (6)

switch_to_locale.php (3.7 KB) - added by yoavf 2 years ago.
switch_to_locale__revisited.php (5.0 KB) - added by tfrommen 3 months ago.
A refreshed version of the WordPress.com functions - PHP 5.2 compatible, and object-oriented.
26511.patch (38.2 KB) - added by tfrommen 3 months ago.
switch_locale.patch (42.9 KB) - added by pbearne 3 months ago.
updated patch with Unit tests (start off)
26511.2.patch (8.4 KB) - added by ocean90 2 months ago.
26511.3.patch (8.8 KB) - added by tfrommen 13 days ago.
Refreshed patch for 4.7

Download all attachments as: .zip

Change History (36)

#1 @nacin
3 years ago

A locale-switching function would be nice to have.

I think this will be something core will need to look into once we start having an in-dashboard language chooser, whereby the pack for that language can be downloaded automatically on selection. At that point, the next logical step would be to allow a user to choose their dashboard language independently from the site's locale.

In theory, this is easy to do. (See the Admin in English plugin.) In practice, it's akin to using the admin in SSL and the frontend using HTTP — core is surely doing something somewhere that causes whatever happens in the admin to trickle into the frontend (so, the equivalent of #15928), and we'll need to figure out those and patch things up.

Anyway, a locale-switching function could be implemented along the lines of switch_to_blog(). As of right now it'd need to be just two things: a filter on 'locale' (there's also a $locale global, though YMMV in the future) followed by a call to load_default_textdomain(). Un-switching is a matter of unhooking the filter and re-calling load_default_textdomain(). (YMMV due to this). That's expensive, though. For core to have this functionality, we should start storing loaded translations on a per-language basis, so as not to obliterate the object in memory, to allow for a switch-back when done without re-calling load_default_textdomain().

#2 @SergeyBiryukov
3 years ago

Previously: #1550

#3 @emzo
3 years ago

  • Cc wordpress@… added

#4 @dimadin
3 years ago

For core strings you can switch language for admin bar, I made a gist with example coincidentally exactly a year ago.

If you want admin bar in en_US and plugins add admin bar items at admin bar hooks, you could have admin bar in en_US by using gettext filters conditionally like in example above.

Problem for not being able to load translations later for plugins and themes is because their translation is loaded once and there is no information about that textdomain (location, type). If we want a language switcher, we need to store that information since I don't see other way to load plugins and themes translations later.

You could actually do this now by hooking to load_*_textdomain() functions but that is complicated.

Note that on wpcom you can set interface language on profile and that will be used on admin bar even if you browse sites in other languages, don't know how do they do that.

#5 @yoavf
2 years ago

On WP.com, we already have something like this that works in a similar way to switch_to_blog() and lets you restore the previous language(s) when you want.

I'm going to look into adapting it for core - it won't work as is because of the way we rely on a single textdomain.

#6 @yoavf
2 years ago

switch_to_locale.php is mostly how we do it on wp.com - I just added incomplete support for additional textdomains. It's incomplete because I can't see a way to know where to get the mo files for plugins and themes when switching the locale.

Thinking aloud: maybe we introduce something like register_textdomain() that stores the location of mo files somewhere for later use. Haven't really thought this through.

This ticket was mentioned in Slack in #polyglots by sergeybiryukov. View the logs.

16 months ago

#8 @rmccue
16 months ago

Related: if you have a multilingual network (i.e. sites have different locales), then things that loop over the sites can break.

get_blog_option( 1, 'WPLANG' ) == '';
get_blog_option( 2, 'WPLANG' ) == 'de_DE';

// The site you start on will have the correct translations
get_current_blog_id() == 1;
get_locale() == 'en_US';
__( 'Hello' ) == 'Hello';

// Switch to a different site, and things start not making sense
switch_to_blog( 2 );
get_locale() == 'de_DE';
__( 'Hello' ) == 'Hello'; // Should be translated "Hallo"

This is causing a bug for us, as we loop over all sites to send a newsletter on each site. When we switch to the site, we generate an email for the site then send it. Turns out we're actually sending out a bunch of emails in the wrong language right now. :)

#9 @ocean90
5 months ago

Related: #32879

This ticket was mentioned in Slack in #core-i18n by ocean90. View the logs.

4 months ago

#11 @SergeyBiryukov
4 months ago

#32879 was marked as a duplicate.

#12 @SergeyBiryukov
4 months ago

  • Milestone changed from Awaiting Review to 4.6

This ticket was mentioned in Slack in #core-i18n by ocean90. View the logs.

4 months ago

#14 follow-up: @ocean90
4 months ago

  • Keywords needs-patch added
  • Summary changed from Separate locale for the admin toolbar to Introduce a locale-switching function

@yoavf, @dd32: Is switch_to_locale.php still the same function which is used on wp.com?

#15 in reply to: ↑ 14 @yoavf
4 months ago

Replying to ocean90:

@yoavf, @dd32: Is switch_to_locale.php still the same function which is used on wp.com?

Yes - this version was just edited to remove wp.com specific references and to add some ( incomplete ) support for multiple text domains.

#16 @pbearne
4 months ago

I took a different approach in #36859 and added a parameter to the constructor to wp_local maybe the efforts can be merged.

The current patch here doesn't fetch a missing language from WP.org where I have got that working in my patch.

3 months ago

A refreshed version of the WordPress.com functions - PHP 5.2 compatible, and object-oriented.

#17 @tfrommen
3 months ago

  • Keywords has-patch dev-feedback added; needs-patch removed

I just attached a refreshed version of the WordPress.com functions.

I took a (PHP 5.2 compatible) object-oriented approach.

The only thing left is getting the according MO file for a textdomain. This should be easy to fix, though, if we were to attach it (the file path) to the MO object.

This ticket was mentioned in Slack in #core by ocean90. View the logs.

3 months ago

3 months ago

This ticket was mentioned in Slack in #core-i18n by tfrommen. View the logs.

3 months ago

This ticket was mentioned in Slack in #core by tfrommen. View the logs.

3 months ago

#21 @pbearne
3 months ago

We have just been working on some unit test and found few problems / bugs with new switcher class

see new patch

3 months ago

updated patch with Unit tests (start off)

#22 @tloureiro
3 months ago

  • In our unit test, when running switch_to_locale(), the global $l10n was not loaded yet. So we had to run a dummy load_text_domain() before making use of the switcher class.
  • switch_to_locale now returns the locale if it runs successfully or false otherwise

#23 @pbearne
3 months ago

  • Keywords has-unit-tests added

The public var $month_genitive was/is not declared in new WP_Locale this is also missing in the old WP_Locale

         * Stores the translated strings for the full month names.
         * array( 'siječnja', 'veljače', 'ožujka', 'travnja', 'svibnja', 'lipnja', 'srpnja', 'kolovoza', 'rujna', 'listopada', 'studenoga', 'prosinca' );
         * @since 4.6.0
         * @var array
        public $month_genitive;

#24 @pbearne
3 months ago

The current function allows you to switch a random locale e.g. xx_XX

Is this a good idea?

If not I can add a test to catch that. e.g.

if ( ! in_array( $locale, get_available_languages() ) ) {
        return false;

But this test doesn't test that we have we have the language file (*.mo) installed so we could add call to the wp_get_available_translations() function ( a file system call - not cheap), But all this tells us is install or not. If it is not installed we shouldn't switch otherwise will have a broken set global locales.

We could get into loading the file from WP.org but this doesn't work on all sites and is slow.

I have come to the conclusion that we should just add the languages files for ALL languages returned via get_available_languages() to WP so we know we can switch and know that the data we need to load the locale is installed.

It's a lot of files but they are small.



This ticket was mentioned in Slack in #core by ocean90. View the logs.

3 months ago

#26 @ocean90
3 months ago

  • Owner set to ocean90
  • Status changed from new to reviewing

#27 @ocean90
2 months ago

In 37889:

I18N: Move the WP_Locale class to its own file.

The new class-wp-locale.php file is loaded in locale.php for backward compatibility purposes.

See #26511.
Fixes #37209.

2 months ago

This ticket was mentioned in Slack in #core by ocean90. View the logs.

2 months ago

#29 @ocean90
2 months ago

  • Milestone changed from 4.6 to Future Release

26511.2.patch is a refresh of 26511.patch after [37889].

Punting, since it didn't get much traction.

13 days ago

Refreshed patch for 4.7

#30 @tfrommen
13 days ago

I just added a refreshed patch for 4.7 (including some minor tweaks).

So, how do we get this thing rolling now? :)

Note: See TracTickets for help on using tickets.