Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add internationalization (i18n) support for PHPMailer error messages #7937

Open
wants to merge 17 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/wp-includes/class-wp-locale-switcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,18 +273,23 @@ private function load_translations( $locale ) {
* @since 4.7.0
*
* @global WP_Locale $wp_locale WordPress date and time locale object.
* @global PHPMailer\PHPMailer\PHPMailer $phpmailer
*
* @param string $locale The locale to change to.
*/
private function change_locale( $locale ) {
global $wp_locale;
global $wp_locale, $phpmailer;

$this->load_translations( $locale );

$wp_locale = new WP_Locale();

WP_Translation_Controller::get_instance()->set_locale( $locale );

if ( $phpmailer instanceof WP_PHPMailer ) {
$phpmailer->SetLanguage();
}

/**
* Fires when the locale is switched to or restored.
*
Expand Down
92 changes: 92 additions & 0 deletions src/wp-includes/class-wp-phpmailer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
/**
* WordPress PHPMailer class.
*
* @package WordPress
* @since 6.8.0
*/

/**
* WordPress PHPMailer class.
*
* Overrides the internationalization method in order to use WordPress' instead.
*
* @since 6.8.0
*/
class WP_PHPMailer extends PHPMailer\PHPMailer\PHPMailer {

/**
* Constructor.
*
* @since 6.8.0
*
* @param bool $exceptions Optional. Whether to throw exceptions for errors. Default false.
*/
public function __construct( $exceptions = false ) {
parent::__construct( $exceptions );
$this->SetLanguage();
}

/**
* Defines the error messages using WordPress' internationalization method.
*
* @since 6.8.0
*
* @return true Always returns true.
*/
public function SetLanguage( $langcode = 'en', $lang_path = '' ) {
$error_strings = array(
'authenticate' => __( 'SMTP Error: Could not authenticate.' ),
'buggy_php' => sprintf(
/* translators: 1: mail.add_x_header. 2: php.ini */
__(
'Your version of PHP is affected by a bug that may result in corrupted messages. To fix it, switch to sending using SMTP, disable the %1$s option in your %2$s, or switch to MacOS or Linux, or upgrade your PHP version.'
),
'mail.add_x_header',
'php.ini'
),
'connect_host' => __( 'SMTP Error: Could not connect to SMTP host.' ),
'data_not_accepted' => __( 'SMTP Error: data not accepted.' ),
'empty_message' => __( 'Message body empty' ),
/* translators: There is a space after the colon. */
'encoding' => __( 'Unknown encoding: ' ),
/* translators: There is a space after the colon. */
'execute' => __( 'Could not execute: ' ),
/* translators: There is a space after the colon. */
'extension_missing' => __( 'Extension missing: ' ),
/* translators: There is a space after the colon. */
'file_access' => __( 'Could not access file: ' ),
/* translators: There is a space after the colon. */
'file_open' => __( 'File Error: Could not open file: ' ),
/* translators: There is a space after the colon. */
'from_failed' => __( 'The following From address failed: ' ),
'instantiate' => __( 'Could not instantiate mail function.' ),
/* translators: There is a space after the colon. */
'invalid_address' => __( 'Invalid address: ' ),
'invalid_header' => __( 'Invalid header name or value' ),
/* translators: There is a space after the colon. */
'invalid_hostentry' => __( 'Invalid hostentry: ' ),
/* translators: There is a space after the colon. */
'invalid_host' => __( 'Invalid host: ' ),
'mailer_not_supported' => __( ' mailer is not supported.' ),
'provide_address' => __( 'You must provide at least one recipient email address.' ),
/* translators: There is a space after the colon. */
'recipients_failed' => __( 'SMTP Error: The following recipients failed: ' ),
/* translators: There is a space after the colon. */
'signing' => __( 'Signing Error: ' ),
/* translators: There is a space after the colon. */
'smtp_code' => __( 'SMTP code: ' ),
/* translators: There is a space after the colon. */
'smtp_code_ex' => __( 'Additional SMTP info: ' ),
'smtp_connect_failed' => __( 'SMTP connect() failed.' ),
/* translators: There is a space after the colon. */
'smtp_detail' => __( 'Detail: ' ),
/* translators: There is a space after the colon. */
'smtp_error' => __( 'SMTP server error: ' ),
/* translators: There is a space after the colon. */
'variable_set' => __( 'Cannot set or reset variable: ' ),
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
);
$this->language = $error_strings;
return true;
}
}
3 changes: 2 additions & 1 deletion src/wp-includes/pluggable.php
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,8 @@ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array()
require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
$phpmailer = new PHPMailer\PHPMailer\PHPMailer( true );
require_once ABSPATH . WPINC . '/class-wp-phpmailer.php';
$phpmailer = new WP_PHPMailer( true );

$phpmailer::$validator = static function ( $email ) {
return (bool) is_email( $email );
Expand Down
2 changes: 1 addition & 1 deletion tests/phpunit/data/languages/de_DE.l10n.php
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
<?php
return ['domain'=>NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['html_lang_attribute'=>'de-DE','text directionltr'=>'ltr','number_format_decimal_point'=>',','number_format_thousands_sep'=>'.','Update %s now'=>'Jetzt %s aktualisieren','[%1$s] Confirm Action: %2$s'=>'[%1$s] Aktion bestätigen: %2$s','[%s] Erasure Request Fulfilled'=>'[%s] Löschauftrag ausgeführt','[%s] Personal Data Export'=>'[%s] Export personenbezogener Daten'],'language'=>'de_DE','x-generator'=>'Poedit 2.2.1'];
return ['domain'=>NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['html_lang_attribute'=>'de-DE','text directionltr'=>'ltr','number_format_decimal_point'=>',','number_format_thousands_sep'=>'.','Update %s now'=>'Jetzt %s aktualisieren','[%1$s] Confirm Action: %2$s'=>'[%1$s] Aktion bestätigen: %2$s','[%s] Erasure Request Fulfilled'=>'[%s] Löschauftrag ausgeführt','[%s] Personal Data Export'=>'[%s] Export personenbezogener Daten', 'You must provide at least one recipient email address.'=>'Du musst mindestens eine Empfänger-E-Mail-Adresse angeben.'],'language'=>'de_DE','x-generator'=>'Poedit 2.2.1'];
Binary file modified tests/phpunit/data/languages/de_DE.mo
Binary file not shown.
4 changes: 4 additions & 0 deletions tests/phpunit/data/languages/de_DE.po
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ msgstr "[%s] Löschauftrag ausgeführt"
#: wp-admin/includes/file.php:2415
msgid "[%s] Personal Data Export"
msgstr "[%s] Export personenbezogener Daten"

#: wp-includes/class-wp-phpmailer.php:71
msgid "You must provide at least one recipient email address."
msgstr "Du musst mindestens eine Empfänger-E-Mail-Adresse angeben."
9 changes: 5 additions & 4 deletions tests/phpunit/includes/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,6 @@
$multisite = $multisite || ( defined( 'WP_TESTS_MULTISITE' ) && WP_TESTS_MULTISITE );
$multisite = $multisite || ( defined( 'MULTISITE' ) && MULTISITE );

// Override the PHPMailer.
require_once __DIR__ . '/mock-mailer.php';
$phpmailer = new MockPHPMailer( true );

if ( ! defined( 'WP_DEFAULT_THEME' ) ) {
define( 'WP_DEFAULT_THEME', 'default' );
}
Expand Down Expand Up @@ -305,6 +301,11 @@ function wp_tests_options( $value ) {
// Load WordPress.
require_once ABSPATH . 'wp-settings.php';

// Override the PHPMailer.
require_once __DIR__ . '/mock-mailer.php';

$phpmailer = new MockPHPMailer( true );

// Delete any default posts & related data.
_delete_all_posts();

Expand Down
16 changes: 15 additions & 1 deletion tests/phpunit/includes/mock-mailer.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
<?php
/**
* Mock PHPMailer class for testing.
*
* @package WordPress
* @subpackage UnitTests
* @since 4.5.0
*/

require_once ABSPATH . 'wp-includes/PHPMailer/PHPMailer.php';
require_once ABSPATH . 'wp-includes/PHPMailer/Exception.php';
require_once ABSPATH . 'wp-includes/class-wp-phpmailer.php';

class MockPHPMailer extends PHPMailer\PHPMailer\PHPMailer {
/**
* Test class extending WP_PHPMailer.
*
* @since 4.5.0
*/
class MockPHPMailer extends WP_PHPMailer {
public $mock_sent = array();

public function preSend() {
Expand Down
66 changes: 66 additions & 0 deletions tests/phpunit/tests/l10n/phpmailerTranslations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* Unit tests covering PHPMailer translations.
*
* @package WordPress
* @subpackage PHPMailer
* @since 6.8.0
*/

/**
* Class Test_PHPMailer_Translations.
*
* Provides tests for PHPMailer translations.
*
* @group mail
* @group i18n
* @group l10n
*
* @since 6.8.0
*/
class Test_PHPMailer_Translations extends WP_UnitTestCase {
/**
* Tests that PHPMailer error message translation works as expected.
*
* @ticket 23311
*/
public function test_missing_recipient_error_message_should_be_translated() {
reset_phpmailer_instance();

$is_switched = switch_to_locale( 'de_DE' );

$phpmailer = tests_retrieve_phpmailer_instance();
$phpmailer->setFrom( '[email protected]' );

try {
$phpmailer->send();
$this->fail( 'Expected exception was not thrown' );
} catch ( PHPMailer\PHPMailer\Exception $e ) {
$error_message = $e->getMessage();
} finally {
if ( $is_switched ) {
restore_previous_locale();
}
}

$this->assertSame(
'Du musst mindestens eine Empfänger-E-Mail-Adresse angeben.',
$error_message,
'Error message is not translated as expected'
);
}

/**
* Test that PHPMailer error message keys are consistent across implementations.
*
* @ticket 23311
*/
public function test_all_error_message_keys_should_be_translated() {
reset_phpmailer_instance();

$phpmailer = new PHPMailer\PHPMailer\PHPMailer();
$wp_phpmailer = tests_retrieve_phpmailer_instance();

$this->assertEqualSets( array_keys( $phpmailer->GetTranslations() ), array_keys( $wp_phpmailer->GetTranslations() ) );
}
}
Loading