Change language by clicking a button

The goal is to offer a button/select drop-down or similar to switch the public interface1) language on the fly.

What I’m searching for

  • Plugin or Theme Code…
  • or Ideas
  • Using a work-around with load_textdomain() would be appreciated to leave translation to .po/.mo files
  • Ideas on how to parse the strings into the interface (ex. ajax/plain php/ini, json, xml files) when not relying on some textdomain function

Note:

1) It’s not about publishing in different languages.

2) I don’t need code to make the actual drop-down/button/whatever. It’s only about the code/system delivering the strings for the UI.

Thanks!

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

By far the best (easiest) way is to use the locale filter (inside get_locale()).

First set up a quick function for retrieving a different language to use on the locale filter.

/**
 * A function returns with returns the user's selectd locale, if stored. 
 */
function wpse35622_get_new_locale($locale=false){
$new_locale = get_user_meta(get_current_user_id(), 'wpse_locale', true);
    if($new_locale)
        return $new_locale;

    return $locale;
}

I’ve left this as a global function, might be handy…? The rest of the plug-in I’ve wrapped inside a class.

It creates a drop-down of possible languages from which you can select.

Drawbacks

  • Searches wp-content/languages for files of the form xx_xx.mo. If it’s not of that form (not all .mo files are) the plug-in won’t pick up on it!
  • The drop down gives a list of the found locales to choose from, but these are displayed in the ‘xx_xx` format of locales, not a human friendly way – any ideas??
  • Does $locale do anything other than language? If so it’s still possible to get the locale the same, but provide alternative translations. It’s a lot messier though…

The code

class SH_Pick_Lang{
    /**
     * A unique name for this plug-in
     */
    static $name ='sh_pick_lang';

    /**
     * Hook the functions
     */
    public function __construct(){

        if( isset($_POST[self::$name]) ){
            add_action('locale',array($this,'update_user'));
        }
        add_filter( 'locale', 'wpse35622_get_new_locale',20 );
        add_action( 'wp_before_admin_bar_render', array( $this, 'admin_bar') );
    }

    /**
     * Update the user's option just in time! Only once mind...
     */
    function update_user($locale){
        $save_locale = $_POST[self::$name];
        update_user_meta(get_current_user_id(), 'wpse_locale', $save_locale);
        remove_filter(current_filter(),__FUNCTION__);
        return $locale;
    }

    /**
     * Add a really horrible looking dropdown menu that I'm sure Kaiser will make look fantastic.
     */
    function admin_bar(){
        global $wp_admin_bar;

        $wp_admin_bar->add_menu( array(
            'id'        => 'shlangpick',
            'title'     => $this->wpse_language_dropown(),
        ) );
    }

    /**
     * Generates a list of available locales.
     * Searches the wp-content/languages folder for files of the form xx_xx.mo
     * 
     * TODO Not all locales are of the form xx_xx.mo - we might miss some.
     * TODO Better way of gettin gthe wp-content/languages folder without a constant?
     */
    function wpse_language_dropown(){
         $name = self::$name;
         $locale = get_locale();
         $langs = get_available_languages();
         $langs[] = 'en_US';

         //For the labels (format_code_lang)
         require_once( ABSPATH . 'wp-admin/includes/ms.php');

         $html = "<form method='post'> ";
         $html .= "<select name='{$name}'>";
         foreach($langs as $lang){
              $label = format_code_lang( $lang );
              $html .= "<option ".selected( $lang, $locale, false)." value='{$lang}'>{$label}</option>";
        }
         $html .= "</select>";
         $html .= get_submit_button('Change Language','secondary', 'submit', true);
         $html .= "</form >";

         return $html;
    }

} // END Class

//Initiate...
$sh_pick_lang = new SH_Pick_Lang();

Method 2

If you can settle for a page refresh, redefining the WPLANG constant could be an option. I’m doing that on two sites with multilingual content where the multilinguality plugin fails to trigger UI translation.

Method 3

http://www.qianqin.de/qtranslate/

is what you need …

Edit I – after comment.
First – thanks for all who contributed in the downvotes torrent.
(this is what happens when one does not visit frequently enough :- ) )

now –
The function that handles the switch is in qtranslate-core.
(starts at line 80 more or less – depends on the version that you want.)

Since you can not look into a NOT OOP code , and I am now with nothing else to do – I took 10 minutes to synthesize , paraphrase compile that non-OOp with yet another non-OOP code for you .

(sorry, – primitive old skool here)

Assuming that I understood the question && Assuming you want the code to be for admin && assuming you will know how to port it to front end if you want && assuming you understand that the code is not optimal :

<?php
/*
Plugin Name: k99 language switcher
Plugin URI: http://www.krembo99.com
Description: Admin Language switcher proof of concept only - do not use in production.
Version: 0.0.0.0.0.0.0.1
Author: Krembo99
Author URI: http://www.krembo99.com
*/ 
?>
<?php function k99_add_language_menu() {
    //  k99_load_ajax_display_functions();
?>  
    <div class="mgmb_help_setting">
    <?php _e('Language:','your_text_domain'); ?>
    <select name="mgmb_language_setting_help" id="mgmb_language_setting_help" onChange="mgmb_set_language_cookies(this.value);" >
        <option value="en_US" <?php if($_COOKIE['k99_userLang']=="en_US"){echo "selected";} ?>><?php _e('English','your_text_domain');?></option>
        <option value="de_DE" <?php if($_COOKIE['k99_userLang']=="de_DE"){echo "selected";} ?>><?php _e('German','your_text_domain');?></option>
        <option value="zh_CN" <?php if($_COOKIE['k99_userLang']=="zh_CN"){echo "selected";} ?>><?php _e('Chinese','your_text_domain');?></option>
    </select>
    </div>
<?php   
}
// Now we set that function up to execute when the help action is called
add_filter('contextual_help', 'k99_add_language_menu');

// I guess this is your mysterious "browser stuff"
function k99_language_change($lang){ 
 global $locale;
 // wp_cache_set( "language", $lang, 'options' );
    if ( isset($_COOKIE['k99_userLang'])) {
      $lang = $_COOKIE['k99_userLang'];
    }
    define( 'WPLANG', $lang );
 if($locale!= $lang) {
    $locale = $lang;
    load_plugin_textdomain('your_text_domain', false, dirname( plugin_basename(__FILE__) ) . '/lang'); // sample use for plugins textdomain
    load_plugin_textdomain('your_text_domain2', false, dirname( plugin_basename(__FILE__) ) . '/lang');
    load_plugin_textdomain('your_text_domain3', false, dirname( plugin_basename(__FILE__) ) . '/lang');
 }
  return $locale;
}
add_filter('locale', 'k99_language_change',99);

////////// +++++++++++++++  START COOKIES CREATION +++++++++++++++//////////////////
// Javascript function set the language cookies
// access external
// @param lang - language code
// @return NULL
// or maybe this is the OP´s mysterious "browser stuff" ??
    function mgmb_print_script() {
    ?>
    <script type="text/javascript" >
    function mgmb_set_language_cookies(lang){   
        var Then = new Date(); 
        Then.setTime(Then.getTime() + 10000*60*60*1000 ); //set cookie expire to 10000 hours cookies (hour*minute*seconds*1000)
        document.cookie = "k99_userLang="+lang+";expires="+ Then.toGMTString();
        window.location.reload();
        } 
        </script>
<?php
} 
add_action('admin_print_scripts', 'mgmb_print_script');  // this is not the right way to do .. but no time now.
?>

REMARKS :

1 – This was built in 10 min. on local machine while at the airport .
The reason why I say this is that the only ready available wordpress installation that I have here is quite old . (2.9 I think).

This means that probably the language menu will appear UNDER the contextual help div, due to the fact that a new div structure was recently introduced (with tabs) – but still it should work.
(I promise to get back to this later if I have time)

If I had more time (and a new wordpress code here ) i would probably integrate this in the new admin-bar with add_action( 'admin_bar_menu', 'k99_add_language_menu_2', 1000 ); (I already promised to get back to this)

2 – you should have the listed languages files inside the “languages” folder in wp-content (better??) or wp-include.
regarding this point – the code is only a proof of concept – and of course if one has more time the menu should be built in a dynamic way and not like done here.

3 – your WPLANG in config should be empty. I am not sure it will work on newer wp versions if a language is already set.

4 – it is a simple synthesized and paraphrased proof of concept built on what was seen in qtranslate code (also old version) – so most of the things are done the “quick” way, not necessarily the “right” way (like adding JS, no dedicated textdomain etc..).

EDIT II

someone is lucky today ! (Flight Delay )

Since you were looking for “ideas” for approaches , here is another famous one .

It will not fit in a plugin, or actually any other non-exclusive environment , but it might give you another direction as how to handle the “Browser stuff”.

This will allow one to get the language with a GET like : <a href="index.php?lang=de" rel="nofollow noreferrer noopener">German</a> or <a href="whatever.php?lang=ml" rel="nofollow noreferrer noopener">my Language</a>

To use , you can create a code (let´s call it wp-langswitch.php )

 session_start();
 if ( isset( $_GET['lang'] ) ) {
    $_SESSION['WPLANG'] = $_GET['lang'];
    define ('WPLANG', $_SESSION[WPLANG]);
 } else {
    if(isset($_SESSION['WPLANG'])) {
        define ('WPLANG', $_SESSION['WPLANG']);
        $_GET['lang'] = $_SESSION['WPLANG'];
    } else {
        if ( isset( $_SERVER["HTTP_ACCEPT_LANGUAGE"] ) ) {
            $languages = strtolower( $_SERVER["HTTP_ACCEPT_LANGUAGE"] );
             $languages = explode( ",", $languages );
            $_SESSION['WPLANG'] = $languages[0];
            $_SESSION['WPLANG'] = str_replace("-", "_", $_SESSION['WPLANG']);
            $_GET['lang'] = substr($_SESSION['WPLANG'],0,2);
            define ('WPLANG', $_SESSION[WPLANG]);
        } else {
            define ('WPLANG', '');
        }
    }
 }

now, in wp-config, just before the WPLANG constant , we need to include our code .

 require_once(dirname(__FILE__).'/wp-langswitch.php');
 define ('WPLANG', '');

Now – obviously it would be better to add some cookies to the mix to store the languages .

EDIT III

I promised to get back to this later – here is how (in a very non-correct and primitive way ) it could be integrated inside the admin-bar (instead of the contextual-help-menu)

 function k99_add_language_menu_bar() {
    global $wp_admin_bar, $wpdb;
    if ( !is_super_admin() || !is_admin_bar_showing() )
        return;
// I am sure you can find a way alone to construct array from reading folder . If not , comment and I will update again.

if($_COOKIE['k99_userLang']=="en_US"){$sel==$_COOKIE['k99_userLang'];} 
if($_COOKIE['k99_userLang']=="de_DE"){$sel==$_COOKIE['k99_userLang'];}
if($_COOKIE['k99_userLang']=="zh_CN"){$sel==$_COOKIE['k99_userLang'];}

    $k99_lang = '';
    $k99_lang .= '<select name="mgmb_language_setting_help" id="mgmb_language_setting_help" onChange="mgmb_set_language_cookies(this.value);" >';
    $k99_lang .= '<option value="en_US" >English</option>';
    $k99_lang .= '<option value="de_DE" >German</option>';
    $k99_lang .= '<option value="zh_CN" >Chinese</option></select>';

    /* Add the main siteadmin menu item */
    $wp_admin_bar->add_menu( array( 'id' => 'Language', 'title' => __( 'language', 'your_text_domain3' ), 'href' => FALSE ) );
    $wp_admin_bar->add_menu( array( 'parent' => 'Language', 'title' => $k99_lang, 'href' => FALSE ) );
}
add_action( 'admin_bar_menu', 'k99_add_language_menu_bar', 999 );

Just replace this function (or add) to the old code (the original NON – OOP non-plugin) .

Like I said, I do not have a new wordpress installation here on local that features admin-bar – but it should work .

(and then again, it might not work…but I am sure you could fix that if you really want – even thought it is not OOP ) 🙂

gotta run now . hope it helps somehow.

EDIT IV – changed edit III to working verion for admin menu bar (at least on my wp 3.4)

since I had no working install of 3.4 – and now I returned and I do – I have edited the Edit III solution – and it works for me .

About the upvotes, I could not care less . And I do not need any “bounties” (whatever those may be..) It was just for the sake of the exercise you shlould maybe give it to the author of qTranslate . 🙂 despite of the fact that it is not OOP – it is a genious plugin with a lot to learn from in a lot of areas . considering the “when” of this plugin release , it is even amazing. worth the indescribably effort of reading a NON OOP code – even if it is not – OOP . And even if it is not correctly indented (good god !).


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x