Skip to main content
7 of 9
added 1141 characters in body
birgire
  • 67.8k
  • 7
  • 119
  • 251

We could try to filter the WPLANG option locale (see e.g. this approach from the related list here on the right by @brasofilo, that's based on this one by @toscho ):

/**
 * Override locale settings for the current (non-admin) user
 */
is_admin() && add_filter( 'locale', function( $locale )
{
    // Modify locale for non-admins (we don't want to override this on the settings pages)
    if( ! current_user_can( 'manage_options' ) )
    {
        // Get admin language for the current user
        $lang = get_user_meta( get_current_user_id(), 'wpse_lang', true );
        
        // Use 'en_US' as default
        $locale = ! empty( $lang ) ? sanitize_text_field( $lang ) : 'en_US';
    }   
    return $locale; 
} );    

where we check if the current user has the wpse_lang user meta key set, with values like is_IS, da_DK, ...

Then we could add the language selection for each user, on the user settings page.

There we could use the wp_dropdown_languages() function, with the get_available_languages() function, to display the select-box for available languages.

Here's an example by @sanchothefat on how we can add custom user settings.

We can display the user language selection with:

/**
 * Display available language dropdown
 */
function wpse_user_language( $user ) 
{
    // Only display for non-admins
    if( current_user_can( 'manage_options' ) )
        return;

    // Get the current 'wp_lang' settings
    $lang = get_user_meta( $user->ID, 'wpse_lang', true ); 
    ?>
    <table class="form-table">
        <tr id="wpse-lang-selection">
            <th scope="row">
               <label for="wpse_lang">
                   <?php _e( 'WPSE' ); ?> - <?php _e( 'Site Language' ); ?>
               </label>
            </th>
            <td><?php wp_dropdown_languages( 
                    [
                        'id'                          => 'wpse_lang',
                        'name'                        => 'wpse_lang',
                        'languages'                   => get_available_languages(),
                        'translations'                => [],
                        'selected'                    => $lang,
                        'show_available_translations' => false,
                    ] 
                );
            ?></td>
        </tr>
    </table>
    <?php
}
add_action( 'show_user_profile', 'wpse_user_language' );
add_action( 'edit_user_profile', 'wpse_user_language' );

Note that here we re-use the Site Language string, because it's translated.

The update part is:

/**
 * Update the 'wp_lang' user settings
 */    
function wpse_user_language_save( $user_id ) 
{
    if( current_user_can( 'edit_user', $user_id ) && isset( $_POST['wpse_lang'] ) )
        return update_user_meta( $user_id, 'wpse_lang', $_POST['wpse_lang'] );
    return false;
}
add_action( 'personal_options_update', 'wpse_user_language_save' );
add_action( 'edit_user_profile_update', 'wpse_user_language_save' );

Here's an example output:

wpse_lang selection

Hopefully you can adjust this to your needs. It would be a good idea to wrap this in a class, where we could initialize it with a custom setup and re-use things. We might also consider removing the is_admin() check to apply this also on the front-end.

birgire
  • 67.8k
  • 7
  • 119
  • 251