Locale switching with a “language” taxonomy

I know that it’s possible to switch the WP locale by using URL paramaters, as described here, but I’m trying to build a method that would entirely rely on a custom “Language” taxonomy.

What I currently have is a simple plugin, that registers the language taxonomy and implements a locale switch if the taxonomy is present:

Read More
<?php
add_action( 'plugins_loaded', 'wpsx_register_taxonomies' );
function wpsx_register_taxonomies() {
register_taxonomy('wpsx_language', array (
                  0 => 'post',
                  1 => 'page',
                ), array( 
                    'hierarchical' => true, 
                    'label' => 'Languages',
                    'singular_label' => 'Language',
                    'show_ui' => true,
                    'rewrite' => false,
                    ) 
                );
}
function wpsx_redefine_locale($locale) {
    global $post;
      if ( taxonomy_exists( 'wpsx_language' )) {
        $locale = 'de_DE'; // this does work !!
        if ( has_term( 'fr', 'wpsx_language' )) {
            $locale = 'fr_FR'; // this does not work yet :(
        }   
     }
     return $locale;
}
add_filter('locale','wpsx_redefine_locale',10);
?>

So the little part that isn’t working is the has_term() test. My impression is that the locale filter is running at an early step in the loading sequence, when the post content isn’t retrieved yet, and therefore conditional tests like is_single() or has_term() won’t return anything.

Can I force the post content to load earlier? Can I delay the locale filter?

I’m unable to figure out a solution for this. On the wp-hackers mailing list, a suggestion was to run global $post; but this didn’t help.


Update: following the suggestion by david.binda, I found a workaround, dropping the taxonomy, and using the post slug as a trigger:

function wpsx89972_redefine_locale($locale) {
    $wpsx_url = $_SERVER['REQUEST_URI'];
    $wpsx_url_lang = substr($wpsx_url, -4); // test for the last 4 chars:
    if ( $wpsx_url_lang == "-fr/") {
        $locale = 'fr_FR';
    } else if ( $wpsx_url_lang == "-en/") { 
        $locale = 'en_US';
    } else { // fallback to default
        $locale = 'de_DE'; 
    }
    return $locale;
}
add_filter('locale','wpsx89972_redefine_locale',10);

This requires the user to rewrite the post slugs, such as “my-post-title-fr” for French, “my-post-title-en” for English, etc. A bit less user-friendly than using language tickboxes, but it keeps the code simple and just works.

So now I have a functional multi-language plugin, in only 13 lines of code 🙂

Still, I will leave this question open for a couple days, to see if anyone comes up with a solution that would make use of the taxonomy…

Related posts

Leave a Reply

2 comments

  1. You might be interested in url_to_postid function

    Used as follows from your wpsx_redefine_locale function:

    $url = $_SERVER['REQUEST_URI'];
    $postid = url_to_postid( $url );
    

    Note that this does not return the post id for custom post types but the function is located in /wp-includes/rewrite.php and might be extended if needed.

    UPDATE: here’s your sample:

    function my_function(){
    if ( ! wp_is_post_revision( $post_id ) ){
    
        // unhook this function so it doesn't loop infinitely
        remove_action('save_post', 'my_function');
    
        // update the post, which calls save_post again
        $my_post_args = array();
        $my_post_args['ID'] = post_id;
        $p = get_post( $post_id );
        $lang_tax = 'my_lang_tax_name';
        $language_terms = get_post_terms( $post_id, $lang_tax );
        $my_post_args['post_name'] = $p->name . '_' . $language_terms[0]->slug;
        wp_update_post( $my_post_args );
    
        // re-hook this function
        add_action('save_post', 'my_function');
    }
    add_action('save_posts', 'my_function');
    

    What have to be done further, but that’s up to you. You have to sanitize the situation when user changed language taxonomy term assigned to post, so you don’t get my-post_de_en instead of my-post_en on post which was before in de and had my-post_de slug. This would require some regular expressions stuff, but you’ll manage that 😉

  2. Here is a better solution that will not change anything in your post, but will only add a meta

    // Set the post language when loading up the page based on the store meta
    function ppl_set_post_language() {
        $postID = url_to_postid( $_SERVER["REQUEST_URI"] );
        if ($postID > 0) {
            $postLanguage = esc_attr( get_post_meta( $postID, '_ppl_post_language', true ) );
            if ( ! empty( $postLanguage ) ) {
                global $locale;
                $locale = $postLanguage;
            }
        }
    }
    // Any call to 'url_to_postid' earlier then 'setup_theme' will generate a fatal error.
    add_action('setup_theme', 'ppl_set_post_language');
    

    For more details check my answer (on my own question) here: Set language per post

    And I have a plugin that makes everything for you (link is in my answer also)