Skip to content
Merged
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
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"symfony/framework-bundle": "^7.0|^8.0",
"symfony/yaml": "^7.0|^8.0",
"symfony/translation": "^7.0|^8.0",
"ext-intl": "*",
"assoconnect/php-quality-config": "^2.2",
"phpstan/phpstan-symfony": "^2"
},
Expand Down
54 changes: 52 additions & 2 deletions tests/TranslationCatalogueTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace AssoConnect\SmtpToolbox\Tests;

use IntlException;
use MessageFormatter;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Yaml;
Expand All @@ -16,10 +18,10 @@ class TranslationCatalogueTest extends TestCase
{
private const string TRANSLATIONS_DIR = __DIR__ . '/../translations';
private const string DOMAIN = 'assoconnect_smtp_toolbox+intl-icu';
private const string REFERENCE_LOCALE = 'en_US';
private const string REFERENCE_LOCALE = 'en';

/** Every locale the catalogues are expected to cover. */
private const array EXPECTED_LOCALES = ['en_US', 'fr_FR', 'es_ES'];
private const array EXPECTED_LOCALES = ['en', 'fr', 'es'];

/** @return iterable<string, array{locale: string}> */
public static function provideLocales(): iterable
Expand Down Expand Up @@ -74,6 +76,44 @@ public function testEveryMessageIsTranslated(string $locale): void
}
}

/**
* The domain carries the +intl-icu suffix, so every message is an ICU pattern. `{{ name }}` is a
* syntax error there, and the translator throws on render rather than at load time.
*/
#[DataProvider('provideLocales')]
public function testEveryMessageIsAValidIcuPattern(string $locale): void
{
$invalid = [];

foreach ($this->messages($locale) as $key => $message) {
if ('' === trim($message)) {
continue;
}

try {
new MessageFormatter($locale, $message);
} catch (IntlException $exception) {
$invalid[] = sprintf('%s (%s)', $key, $exception->getMessage());
}
}

self::assertSame([], $invalid, sprintf('Invalid ICU pattern(s) in the %s catalogue.', $locale));
}

#[DataProvider('provideLocales')]
public function testEveryMessageCarriesTheReferencePlaceholders(string $locale): void
{
$messages = $this->messages($locale);

foreach ($this->messages(self::REFERENCE_LOCALE) as $key => $reference) {
self::assertSame(
self::placeholders($reference),
self::placeholders($messages[$key] ?? ''),
sprintf('Message "%s" does not carry the same placeholders in %s.', $key, $locale)
);
}
}

private static function cataloguePath(string $locale): string
{
return sprintf('%s/%s.%s.yml', self::TRANSLATIONS_DIR, self::DOMAIN, $locale);
Expand Down Expand Up @@ -113,4 +153,14 @@ private static function flatten(array $catalogue, string $prefix = ''): array

return $messages;
}

/** @return list<string> */
private static function placeholders(string $message): array
{
preg_match_all('/\{(\w+)\}/', $message, $matches);
$placeholders = array_unique($matches[1]);
sort($placeholders);

return $placeholders;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ bounce:
none: ""
review: "Please check the email address for typo."
invalid_address:
no_at_symbol: "The email address {{ email }} is missing the @ symbol"
no_mx_servers: "No email servers are set up for {{ domain }}"
no_at_symbol: "The email address {email} is missing the @ symbol"
no_mx_servers: "No email servers are set up for {domain}"
unknown_user: >
The email address {{ email }} doesn't exist at {{ domain }} :
{{ smtpResponse }}
The email address {email} doesn't exist at {domain}:
{smtpResponse}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ bounce:
none: ""
review: "Compruebe si la dirección de correo electrónico contiene alguna errata."
invalid_address:
no_at_symbol: "A la dirección {{ email }} le falta el símbolo @"
no_mx_servers: "No hay ningún servidor de correo configurado para {{ domain }}"
no_at_symbol: "A la dirección {email} le falta el símbolo @"
no_mx_servers: "No hay ningún servidor de correo configurado para {domain}"
unknown_user: >
La dirección {{ email }} no existe en {{ domain }} :
{{ smtpResponse }}
La dirección {email} no existe en {domain}:
{smtpResponse}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ bounce:
none: ""
review: "Vérifiez l'adresse enregistrée : elle contient peut-être une faute de frappe."
invalid_address:
no_at_symbol: "L'adresse {{ email }} ne contient pas le signe @"
no_mx_servers: "Aucun serveur email n'est configuré pour le domain {{ domain }}"
no_at_symbol: "L'adresse {email} ne contient pas le signe @"
no_mx_servers: "Aucun serveur email n'est configuré pour le domain {domain}"
unknown_user: >
L'adresse {{ email }} n'existe pas chez {{ domain }} :
{{ smtpResponse }}
L'adresse {email} n'existe pas chez {domain} :
{smtpResponse}
Loading