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
116 changes: 116 additions & 0 deletions tests/TranslationCatalogueTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

declare(strict_types=1);

namespace AssoConnect\SmtpToolbox\Tests;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Yaml;

/**
* Every catalogue must cover the reference locale's messages, each in a wording of its own. Neither a
* missing catalogue nor an untranslated message fails at runtime, so this test is what guards them.
*/
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';

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

/** @return iterable<string, array{locale: string}> */
public static function provideLocales(): iterable
{
foreach (self::EXPECTED_LOCALES as $locale) {
yield $locale => ['locale' => $locale];
}
}

#[DataProvider('provideLocales')]
public function testCatalogueExists(string $locale): void
{
self::assertFileExists(self::cataloguePath($locale));
}

#[DataProvider('provideLocales')]
public function testCatalogueCoversEveryReferenceMessage(string $locale): void
{
self::assertSame(
array_keys($this->messages(self::REFERENCE_LOCALE)),
array_keys($this->messages($locale)),
sprintf('The %s catalogue does not cover the same messages as the %s one.', $locale, self::REFERENCE_LOCALE)
);
}

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

foreach ($this->messages(self::REFERENCE_LOCALE) as $key => $reference) {
$message = trim($messages[$key] ?? '');

// Some messages are deliberately blank, so emptiness is only a gap where the reference has wording
if ('' === trim($reference)) {
self::assertSame('', $message, sprintf('Message "%s" should stay blank.', $key));
continue;
}

self::assertNotSame('', $message, sprintf('Message "%s" has no %s translation.', $key, $locale));

if (self::REFERENCE_LOCALE === $locale) {
continue;
}

// A catalogue copied from the reference locale and left untranslated clears the emptiness check
self::assertNotSame(
trim($reference),
$message,
sprintf('Message "%s" still reads as its %s wording.', $key, self::REFERENCE_LOCALE)
);
}
}

private static function cataloguePath(string $locale): string
{
return sprintf('%s/%s.%s.yml', self::TRANSLATIONS_DIR, self::DOMAIN, $locale);
}

/** @return array<string, string> */
private function messages(string $locale): array
{
$catalogue = Yaml::parseFile(self::cataloguePath($locale));
self::assertIsArray($catalogue, sprintf('The %s catalogue is not a YAML mapping.', $locale));

$messages = self::flatten($catalogue);
ksort($messages);

return $messages;
}

/**
* @param array<mixed> $catalogue
*
* @return array<string, string>
*/
private static function flatten(array $catalogue, string $prefix = ''): array
{
$messages = [];

foreach ($catalogue as $key => $value) {
$path = '' === $prefix ? (string) $key : $prefix . '.' . $key;

if (is_array($value)) {
$messages += self::flatten($value, $path);
continue;
}

$messages[$path] = (string) $value;
}

return $messages;
}
}
18 changes: 18 additions & 0 deletions translations/assoconnect_smtp_toolbox+intl-icu.es_ES.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
bounce:
reason:
inactive: "El buzón del destinatario ha sido desactivado."
quota: "El buzón del destinatario está lleno y no puede aceptar nuevos correos electrónicos por el momento"
none: "No hemos podido interpretar el motivo del fallo de envío comunicado por el servidor de correo"
other: ""
spam: "El sistema de correo del destinatario ha marcado el mensaje como spam y se niega a entregarlo."
unknown_user: "Esta dirección de correo electrónico no existe."
tips:
contact: "Informe al destinatario de este problema para que pueda resolverse."
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 }}"
unknown_user: >
La dirección {{ email }} no existe en {{ domain }} :
{{ smtpResponse }}
Loading