How to force WordPress to temporarily switch locale (using qTranslate)?

I have a multi-language store running WooCommerce and qTranslate, and am trying to setup multi-language customer emails. The problem is, the “order complete” email gets sent from the admin backend, and it is sent in the language the backend is used in, not in the language that the order was initially made in.

What I’ve got working so far is storing the order locale as a custom field, and plugging my code into WooCommerce’s email sending mechanism. What I need to do now is to dynamically switch the current locale to the one saved in the order data, dispatch the email, and switch it back.

Read More

Currently, I’m trying to force locale in a multitude of places, but none of them work. Here’s the current code:

// get order language and its locale from qTranslate config
$order_custom_data = get_post_custom($order_id);
$new_locale = $order_custom_data['Customer Locale'][0];

// save current locale
$old_locale = get_locale();

// set the current locale and send email with it active
setlocale(LC_ALL, $new_locale);
global $q_config, $locale;
$locale = $new_locale;
$q_config['language'] = substr($new_locale, 0, 2);
// dispatch email
global $wc_cle_wc_email;
$wc_cle_wc_email->customer_processing_order($order_id);

// set the old locale back
$q_config['language'] = substr($old_locale, 0, 2);
$locale = $old_locale;
setlocale(LC_ALL, $old_locale);

Debug output shows the current and order locales being read correctly, and a get_locale() call parallel to customer_processing_order() outputs the order locale instead of the current one. But the email generated by the customer_processing_order() call is built with the current language strings instead of those in the order language. Any ideas how to work around this?

Related posts

Leave a Reply

2 comments

  1. And I got it. What was missing was re-loading the text domain for WooCommerce, that was loaded with the current locale at initialization:

    // set the current locale and send email with it active
    unload_textdomain('woocommerce');
    setlocale(LC_ALL, $new_locale);
    global $q_config, $locale, $woocommerce;
    $locale = $new_locale;
    $q_config['language'] = substr($new_locale, 0, 2);
    $woocommerce->load_plugin_textdomain();
    
    global $wc_cle_wc_email;
    $wc_cle_wc_email->customer_completed_order($order_id);
    
    // set the old locale back
    unload_textdomain('woocommerce');
    $q_config['language'] = substr($old_locale, 0, 2);
    $locale = $old_locale;
    setlocale(LC_ALL, $old_locale);
    $woocommerce->load_plugin_textdomain();
    

    Some of the calls setting the locale variables are probably redundant and/or simply unnecessary, but this works.

  2. Ok, here is a slightly more complete answer for those who stumble upon this later.

    add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
    function custom_override_checkout_fields( $fields ) {
             $fields['order']['language']['placeholder'] = '';
             $fields['order']['language']['type'] = 'text';
             $fields['order']['language']['label'] = 'language';
             $fields['order']['language']['class'] = array('hidden'); 
             $fields['order']['language']['default'] = qtrans_getLanguage();
         return $fields;
    }
    

    And then… you need to save that field on checkout, which is simple:

    /**
     * Save the language to the order (despite what woocommerce doc says this is required)
     */
    add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );
    function my_custom_checkout_field_update_order_meta( $order_id ) {
        if ( ! empty( $_POST['language'] ) ) {
            update_post_meta( $order_id, 'language', sanitize_text_field( $_POST['language'] ) );
        }
    }
    

    And then… (this part is a bit hacky, but i hook into the beginning of the email creation (the subject) and then change the language to the order’s language). I don’t think you really need to worry about changing it back since once the thread dies it will switch back to default. And it should just die right after sending this email because this only happens on a callback.

    add_filter('woocommerce_email_subject_customer_completed_order', 'waspdigital_order_complete_language_fix', 1, 2);
    function waspdigital_order_complete_language_fix( $subject, $order ){
        global $woocommerce;
        $new_locale = get_post_meta( $order->id, 'language', true);
        // set the current locale and send email with it active
        unload_textdomain('woocommerce');
        setlocale(LC_ALL, $new_locale);
        global $q_config, $locale, $woocommerce;
        $locale = $new_locale;
        $q_config['language'] = substr($new_locale, 0, 2);
        $woocommerce->load_plugin_textdomain();
    
    /*
        // set the old locale back
        unload_textdomain('woocommerce');
        $q_config['language'] = substr($old_locale, 0, 2);
        $locale = $old_locale;
        setlocale(LC_ALL, $old_locale);
        $woocommerce->load_plugin_textdomain();
    */
    
        return $subject;
    }