diff --git a/tests/TranslationCatalogueTest.php b/tests/TranslationCatalogueTest.php new file mode 100644 index 0000000..fa4c1b8 --- /dev/null +++ b/tests/TranslationCatalogueTest.php @@ -0,0 +1,116 @@ + */ + 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 */ + 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 $catalogue + * + * @return array + */ + 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; + } +} diff --git a/translations/assoconnect_smtp_toolbox+intl-icu.es_ES.yml b/translations/assoconnect_smtp_toolbox+intl-icu.es_ES.yml new file mode 100644 index 0000000..5d5f1e6 --- /dev/null +++ b/translations/assoconnect_smtp_toolbox+intl-icu.es_ES.yml @@ -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 }}