Skip to content

Instantly share code, notes, and snippets.

@dartrax
Last active September 29, 2022 19:14
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dartrax/9387937ef9752ab3f70c4fde03c9d946 to your computer and use it in GitHub Desktop.
Save dartrax/9387937ef9752ab3f70c4fde03c9d946 to your computer and use it in GitHub Desktop.
Translate WooCommerce and WooCommerce Germanized mails into order language with TranslatePress before sending. Note: As of TranslatePress Version 2.3.5, this functionality was implemented natively by TranslatePress, making this Code obsolete. Read more here: https://translatepress.com/docs/translating-woocommerce-emails/
// Save the current language in post_meta when checkout is processed (used to identify correct Email language)
add_action('woocommerce_checkout_update_order_meta', 'dartrax_save_language_on_checkout', 10, 2 );
function dartrax_save_language_on_checkout( $order_id, $posted ) {
if( ! class_exists('TRP_Translate_Press') ) return '';
global $TRP_LANGUAGE;
update_post_meta( $order_id, 'order_language', $TRP_LANGUAGE );
}
// Woocommerce Germanized Mails
add_action( 'woocommerce_gzd_shipment_status_draft_to_shipped_notification', 'dartrax_prepare_locale_for_Mail_with_shipment_id', 5, 1 );
add_action( 'woocommerce_gzd_shipment_status_processing_to_shipped_notification', 'dartrax_prepare_locale_for_Mail_with_shipment_id', 5, 1 );
add_action( 'woocommerce_gzd_return_shipment_status_draft_to_processing_notification', 'dartrax_prepare_locale_for_Mail_with_shipment_id', 5, 1 );
add_action( 'woocommerce_gzd_return_shipment_status_requested_to_processing_notification', 'dartrax_prepare_locale_for_Mail_with_shipment_id', 5, 1 );
add_action( 'woocommerce_gzd_return_shipment_status_processing_to_delivered_notification', 'dartrax_prepare_locale_for_Mail_with_shipment_id', 5, 1 );
add_action( 'woocommerce_gzd_return_shipment_status_shipped_to_delivered_notification', 'dartrax_prepare_locale_for_Mail_with_shipment_id', 5, 1 );
function dartrax_prepare_locale_for_Mail_with_shipment_id( $shipment_id ) {
// get order_id from shipment and proceed with that
if( $shipment = wc_gzd_get_shipment( $shipment_id ) )
dartrax_prepare_locale_for_Mail_with_order_id( $shipment->get_order_id() );
}
// Woocommerce Shipment Mails
add_action( 'woocommerce_order_status_processing_to_cancelled_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_on-hold_to_cancelled_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_completed_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_pending_to_on-hold_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_failed_to_on-hold_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_cancelled_to_on-hold_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_cancelled_to_processing_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_failed_to_processing_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_on-hold_to_processing_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_pending_to_processing_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_fully_refunded_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_partially_refunded_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_pending_to_failed_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_on-hold_to_failed_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_pending_to_completed_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_failed_to_completed_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
add_action( 'woocommerce_order_status_cancelled_to_completed_notification','dartrax_prepare_locale_for_Mail_with_order_id', 5, 1 );
function dartrax_prepare_locale_for_Mail_with_order_id( $order_id ) {
// Get language code that may be stored in post meta data
$lang_code = get_post_meta($order_id, 'order_language', true);
if( $lang_code == '' || ! class_exists('TRP_Translate_Press') ) return '';
// Set it as current active language for translatepress
global $TRP_LANGUAGE;
$TRP_LANGUAGE = $lang_code;
}
// Woocommerce Mails when resend by Admin
add_action( 'woocommerce_before_resend_order_emails','dartrax_prepare_locale_for_resend_Mails', 5, 2 );
function dartrax_prepare_locale_for_resend_Mails( $order, $mail_type ) {
// First type belongs to WooCommerce, last two types belong to WooCommerce Germanized
if($mail_type == 'customer_invoice' || $mail_type == 'customer_paid_for_order' || $mail_type == 'customer_processing_order')
dartrax_prepare_locale_for_Mail_with_order_id( $order->get_id() );
}
// Woocommerce Note to customer Mail
add_action( 'woocommerce_new_customer_note_notification','dartrax_prepare_locale_for_note_Mails', 5, 1 );
function dartrax_prepare_locale_for_note_Mails( $note_and_order_id ) {
// get order_id from argument array and proceed with that
dartrax_prepare_locale_for_Mail_with_order_id( $note_and_order_id['order_id'] );
}
// Prevent Woocommerce Germanized from filtering the Translatepress Shortcut when legal pages are used in emails
add_filter( 'woocommerce_gzd_email_attachment_content_shortcodes_allowed', function( $shortcodes_allowed ) {
array_push($shortcodes_allowed, "trp_language");
return $shortcodes_allowed;
} );
// Override Locale when WooCommerce sends an eMail
add_filter( 'woocommerce_email_setup_locale', function() {
if( ! class_exists('TRP_Translate_Press') ) return '';
// Override translatepress 'locale'-function because that does not work in Admin interface
add_filter('locale','dartrax_force_trp_locale', 99999 + 1);
// Switch text domains to load the correct .po/.mo-file based translations
global $TRP_LANGUAGE;
switch_text_domains( $TRP_LANGUAGE );
return false;
} );
add_filter( 'woocommerce_email_restore_locale', function() {
// Undo overriding of translatepress' 'locale'-function
remove_filter('locale','dartrax_force_trp_locale', 99999 + 1);
return true;
} );
// Override translatepress 'locale'-function because that does not deliver $TRP_LANGUAGE in Admin interface
function dartrax_force_trp_locale($locale) {
global $TRP_LANGUAGE;
return $TRP_LANGUAGE;
}
// Override 'plugin_locale'-function so Woocommerce and Woocommerze Germanized won't use the admin profile language
function dartrax_force_woo_locale($locale, $plugin) {
global $TRP_LANGUAGE;
return $plugin == 'woocommerce' || $plugin == 'woocommerce-germanized' ? $TRP_LANGUAGE : $locale;
}
// Switch to another text domain. Inspired by https://gist.github.com/Jon007/5b90e78289899bc28e9c39c12ef56e60
function switch_text_domains( $language ) {
if ( class_exists( 'TRP_Translate_Press' ) && class_exists( 'WooCommerce' ) && class_exists( 'WooCommerce_Germanized' ) ) {
global $locale, $woocommerce, $woocommerce_germanized;
// unload plugin's textdomains
unload_textdomain( 'default' );
unload_textdomain( 'woocommerce' );
unload_textdomain( 'woocommerce-germanized' );
// set locale to order locale
$locale = apply_filters( 'locale', $language );
// Woocommerce and Woocommerce Germanized use the admin profile language instead of the side language. Override with the desired language
add_filter('plugin_locale', 'dartrax_force_woo_locale', 10, 2);
// (re-)load plugin's textdomain with order locale
load_default_textdomain( $language );
$woocommerce->load_plugin_textdomain();
$woocommerce_germanized->load_plugin_textdomain();
$wp_locale = new \WP_Locale();
// Clean up
remove_filter('plugin_locale', 'dartrax_force_woo_locale', 10);
}
}
@egcmi
Copy link

egcmi commented Mar 28, 2021

Hi @dartrax, thanks for this gist.
I want to switch to TranslatePress and I'm having issues translating emails. The order confirmation email is sent in the user language, however all subsequent emails are sent in the default language (English).
After turning online for support I found this gist. I tried adding this code to my functions.php in WordPress, hoping it would solve my problem, but I can't get it to work properly. I can see that _order_language is successfully stored in the post meta in the database, but emails are unfortunately still sent in English (except order confirmation, as before), instead of the customer language.
Have you tested this code on your site and have you been successful with it? Do you have any insights on how I can get it to work? I am available for more clarifications if needed. Thank you very much for your time.

@dartrax
Copy link
Author

dartrax commented Mar 28, 2021

Hi @egcmi,
thanks for your interest!
Yes, I‘m using it successfully on my site. However, I only tested with a testuser and did not check every mail yet because I did not have any international customer since I implemented this in the last couple of weeks. There may be bugs.

But lets find out why it seems not to work for you.
What translatePress Version do you use?
Do you have the WooCommerce Germanized Plugin, and which version? If you do not use WooCommerce Germanized, you must use my other gist, because this one will not pass
if(class_exists( 'WooCommerce_Germanized' ))
in that case.

@egcmi
Copy link

egcmi commented Mar 28, 2021

Hi @dartrax, thank you for getting back so quickly.
I am using TranslatePress Version 1.9.7, WooCommerce Version 5.1.0 and WordPress version 5.7.
I did not have WooCommerce Germanized when I wrote the first comment, but I had tried your other gist without success.
Now I tried installing WooCommerce Germanized (latest version, 3.3.7) alongside this gist, but it still did not work. The tests I did were using it_IT as language, which is successfully stored in the database, so we know at least this part is working :)
As mentioned earlier, the first email (order received) is sent in the correct language (it_IT), but this is the standard behaviour of TranslatePress. Then I tried changing the order status from on hold to processing, to cancelled, then back to processing and also manually resend the order confirmation email. The emails were all sent in the default language, which is English.

@dartrax
Copy link
Author

dartrax commented Mar 28, 2021

Hi @egcmi,
I've updated my setup to be on par with your version numbers.
We should concentrate on one mail first and try to get this out in correct language. Let's take the "Your ... order #... has been cancelled" mail. In my WooCommerce Settings, there are two mails for this, one for the customer and one for myself, the site/shop administrator. Please be sure to look for the customers mail, because only that will be translated, not the one for the shop administrator.

First thing to check is if the locale gets correctly read from database and set for translatePress. Please set the subject for the customer's cancellation mail in WooCommerce Mail Settings to this value:

[trp_language language="it_IT"]Italian[/trp_language][trp_language language="en_US"]English[/trp_language]

Change the order status of the test customer's order to processing and to cancelled. Is the Subject of the customer's mail "Italian" or "English" (or empty)?

@egcmi
Copy link

egcmi commented Mar 31, 2021

Hi Dartrax,
Thank you very much for the inputs. I got it to work now on the "Your ... order #... has been cancelled" mail, the subject is either "Italian" or "German". Now I'd need to understand how to structure the email itself. Do I need to use the shortcodes there too in order to make it work? Or can it be done with a translation file? In the first case, could you maybe share an MWE on how you would structure it? Thank you.

@dartrax
Copy link
Author

dartrax commented Mar 31, 2021

Hi @egcmi,
great, that means that the language is correctly read from the database.

No, you do not need to use the shortcodes. You only need them if you want custom content in those fields, or if you attach pages to the content of the mails. I have pages like privacy or return policies that I include in the content. In order to translate those on the page and in the mails, I use the shortcodes to wrap them around the whole page content.

If you leave the fields blank, the woocommerce default values will be used, and that will be translated with use of the switch_text_domains function in my gist. Also, the product table (Product/Quantity/Price) can be translated only by use of the translation files.

Can you confirm that the product table and the other default values are not translated, only the part with the shortcodes? I'll give you instructions how to further track down the problem then.

@egcmi
Copy link

egcmi commented Mar 31, 2021

Hello @dartrax,
Thank you for your quick reply.
Only the part with the shortcode is being translated, as well as the product name. The remaining part of the email is not unfortunately.
The translation files do seem to exist, otherwise the very first order confirmation email wouldn't be sent out already translated into Italian.
Thanks a lot for your help.

@dartrax
Copy link
Author

dartrax commented Apr 1, 2021

Hi @egcmi,
I've changed languages at my testing setup, so I also have english default and italian with the test order now. For me, it works. So I added some debug messages that hopefully will show where it does not work as it should on your site. I also made a first bet on where the problem might be and made a little change to that piece of code. Could you please try the following:

  1. enable debug log: In wp-config.php, find the line define('WP_DEBUG', false); and change it to define('WP_DEBUG', true);
  2. swap the switch_text_domains-function from the gist above with this one:
function switch_text_domains( $language ) {
	error_log('switch to ' . $language . ' start');
	if ( class_exists( 'TRP_Translate_Press' ) && class_exists( 'WooCommerce' ) && class_exists( 'WooCommerce_Germanized' )) {
		global $locale, $woocommerce, $woocommerce_germanized;
		// unload plugin's textdomains
		unload_textdomain( 'default' );
		unload_textdomain( 'woocommerce' );
		unload_textdomain( 'woocommerce-germanized' );
		// set locale to order locale
		error_log('locale is ' . $locale );
		$localeFiltered = apply_filters( 'locale', $language );
		error_log('language gets filtered to ' . $localeFiltered );
		//$locale = apply_filters( 'locale', $language );
		$locale = $language;
		// (re-)load plugin's textdomain with order locale
		load_default_textdomain( $language );
		$woocommerce->load_plugin_textdomain();
		$woocommerce_germanized->load_plugin_textdomain();
		$wp_locale = new \WP_Locale();
	}
	error_log('switch to ' . $locale . ' end');
}
  1. trigger sending of the cancellation mail. Check if it still is not translated properly.
  2. post content of the wp-content/debug.log file.

@egcmi
Copy link

egcmi commented Apr 5, 2021

Hello @dartrax,
Thank you for your suggestions, which helped a lot.
In the log file I could see that something was going on with the Divi BodyCommerce plugin. I disabled and re-enabled the email templates generated using this plugin and the emails started to be translated finally.
As we also create orders manually from the wp-admin interface, would there be any possibility to add a custom field on the order's page with the customer's language? If not, a workaround will be to create the order on the front-end in a specific language and then edit it afterwards.
Thanks a lot.

@dartrax
Copy link
Author

dartrax commented Apr 5, 2021

Hi @egcmi,
thank you for your suggestion. I've just learned that if I remove the underscore in front of '_order_language', it will show up as "Custom Field" in the order edit/create dialog. I'll update the gist removing that underscore, as I think it is generally a good idea to have that information at hand when dealing with an order. You can then set the order language in the "Custom Fields" section.

All you need to do is to replace '_order_language' with 'order_language', in the code as well as in your database' postmeta table in the meta_key column.

@dartrax
Copy link
Author

dartrax commented Jul 13, 2021

Fix: Mail when a note to customer is sent wasn't translated

@Nieder-hu
Copy link

Hi @dartrax , I ran into the same problem as @egcmi , so the shortcode is translating properly but everything else stays in English. Error log doesn't seem to be problematic:

[14-Feb-2022 11:10:17 UTC] switch to de_DE start
[14-Feb-2022 11:10:17 UTC] locale is de_DE
[14-Feb-2022 11:10:17 UTC] language gets filtered to de_DE
[14-Feb-2022 11:10:17 UTC] switch to de_DE end

Any idea how to resolve?

@dartrax
Copy link
Author

dartrax commented Feb 14, 2022

Hi @Nieder-hu,
just for not confusing others: When the locale is actually switched, the debug log should look like this (switching form de_DE_formal to it_IT in this example):

[18-Jul-2021 18:18:25 UTC] switch to it_IT start
[18-Jul-2021 18:18:25 UTC] locale is de_DE_formal
[18-Jul-2021 18:18:25 UTC] language gets filtered to it_IT
[18-Jul-2021 18:18:26 UTC] switch to it_IT end

But since you try to get the mails translated into german anyway, the fact that it seems to switch from german to german is not the main problem here.

My guess is that the german language mo/po files are not present, so while it tries to deliver translated mails it falls back to english because it can't find the translations. Please be aware that there are different german language files, de_DE (for "Du") is not the same as de_DE_formal (for "Sie").
May be you could try switching the language using "General settings -> Language" and try to trigger an email after the sites default language was set to german. If this works, the german language files are present (or have been installed by this procedure) and it should continue to work even after you switch back the default language to english.

@Nieder-hu
Copy link

Thanks @dartrax , it seems that actual admin user language somehow overwrites the order_language field. If I set my admin profile to German everything is sent in German, but once it's English it is sending everything (instead of the first email) in English, however the order was made on the German site. At least, error log is now OK.

[14-Feb-2022 13:53:10 UTC] switch to en_US start
[14-Feb-2022 13:53:10 UTC] locale is de_DE
[14-Feb-2022 13:53:10 UTC] language gets filtered to en_US
[14-Feb-2022 13:53:10 UTC] switch to en_US end

@dartrax
Copy link
Author

dartrax commented Feb 14, 2022

it seems that actual admin user language somehow overwrites the order_language field.

Hi @Nieder-hu,
by "somehow overwrites" do you mean that it actually changes its value in the Database?
The order_language field is the place where the language used by the user who checks out an order is stored. It should only be read and written by my code above. Do you have any other plugin, like wpml or woocommerce multilingual that also uses this parameter? You can do a search and replace in the code of this gist and use any other name, like "dartrax_order_language" instead of "order_language" to rule out any conflict.

Please check if that parameter is set to "de_DE" for the order in question first.

If that's the case, the Log should read:

[14-Feb-2022 13:53:10 UTC] switch to de_DE start
[14-Feb-2022 13:53:10 UTC] locale is en_US
[14-Feb-2022 13:53:10 UTC] language gets filtered to de_DE
[14-Feb-2022 13:53:10 UTC] switch to de_DE end

...and not the other way around!

If I set my admin profile to German everything is sent in German

So the translation files are there. Good to have that checked!

@Nieder-hu
Copy link

Hi @dartrax ,
no, the meta field value is unchanged (de_DE). Even if I change its name to something else in the code, it doesn't change. The main language is German, but I use the wp admin interface in English. So I got a nice log, that says everything should be totally German, but in reality, emails are sent in English. I tried to deactivate all the plugins and so on but nothing works so far. Also tried to set order language to en_US and switch wp admin to German. In that case, emails are German. I really appreciate your help, because I'm totally lost about what could be wrong.

[15-Feb-2022 04:26:17 UTC] switch to de_DE start
[15-Feb-2022 04:26:17 UTC] locale is de_DE
[15-Feb-2022 04:26:17 UTC] language gets filtered to de_DE
[15-Feb-2022 04:26:17 UTC] switch to de_DE end

@dartrax
Copy link
Author

dartrax commented Feb 15, 2022

Hi @Nieder-hu,
I‘d like to make a test environment with the same settings as you have to see if I can reproduce that issue. Can you give me the following information:

Wordpress Version
Woocommerce Version
Translatepress Version
Translatepress Business Version if installed
Germanized Version
Wordpress Main language in general settings
Admin user language in user profile

I‘m not sure if it has something to do with different Page default/Admin languages (a case that I did not test yet) or with plugin versions (I still use Woocommerce 5.x).

@Nieder-hu
Copy link

Hi @dartrax , thanks for your help.

WordPress version: 5.9
WooCommerce version: 6.2.0
TranslatePress - Developer: 1.0.9
TranslatePress - Multilingual: 2.2.0
Germanized for WooCommerce: 3.83.
WP main language: German (de_DE)
Admin language: English (en_US)

@dartrax
Copy link
Author

dartrax commented Feb 20, 2022

Hi @Nieder-hu,
finally I was able to reproduce your issue. The culprit is the admin user locale not being the sites default locale. The function $woocommerce->load_plugin_textdomain() uses determine_locale(), which returns the user locale if the user is the admin user instead of the site default locale (which was set to the order_language before). I've added a filter to the plugin_locale hook, please tell me if that fixes your problem.

Fix: When the admin profile language did not match the side default language, instead of the order language the admin profile language was used for the translations covered by the woocommerce .mo/.po-files.

@Nieder-hu
Copy link

Hi @dartrax , thanks it works well.

@dartrax
Copy link
Author

dartrax commented Feb 26, 2022

Fix: Since a recent update of WooCommerce Germanized, the trp_language conditional shortcode got ignored when used in legal pages included with mails. This resulted in mails in which, for example, the terms and conditions occurred several times in a row in all available languages. This is fixed now.

@dartrax
Copy link
Author

dartrax commented Sep 29, 2022

For everyone's interest:
I've used the new Mail localisation feature that was natively build into TranslatePress for a while now, and I did not encounter any problems.

Just this little peace of code is still necessary, if you want to use the TranslatePress' conditional shortcuts in Emails, because otherwise they get filtered by the Germanized Extension.

// Prevent Woocommerce Germanized from filtering the Translatepress Shortcut when legal pages are used in emails
add_filter( 'woocommerce_gzd_email_attachment_content_shortcodes_allowed', function( $shortcodes_allowed ) {
	array_push($shortcodes_allowed, "trp_language");
	return $shortcodes_allowed;
} );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment