diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index d2f8a5e796..32a513cc32 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -7430,26 +7430,6 @@ parameters: count: 1 path: src/contracts/Repository/Values/ObjectState/ObjectStateCreateStruct.php - - - message: "#^Method Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Translation\\\\Message\\:\\:__construct\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" - count: 1 - path: src/contracts/Repository/Values/Translation/Message.php - - - - message: "#^Property Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Translation\\\\Message\\:\\:\\$values type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/contracts/Repository/Values/Translation/Message.php - - - - message: "#^Method Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Translation\\\\Plural\\:\\:__construct\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" - count: 1 - path: src/contracts/Repository/Values/Translation/Plural.php - - - - message: "#^Property Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\Translation\\\\Plural\\:\\:\\$values type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/contracts/Repository/Values/Translation/Plural.php - - message: "#^Class Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\URL\\\\SearchResult implements generic interface IteratorAggregate but does not specify its types\\: TKey, TValue$#" count: 1 diff --git a/src/contracts/Repository/Values/Translation/Message.php b/src/contracts/Repository/Values/Translation/Message.php index 15ebe3d207..66c276a175 100644 --- a/src/contracts/Repository/Values/Translation/Message.php +++ b/src/contracts/Repository/Values/Translation/Message.php @@ -4,6 +4,7 @@ * @copyright Copyright (C) Ibexa AS. All rights reserved. * @license For full copyright and license information view LICENSE file distributed with this source code. */ +declare(strict_types=1); namespace Ibexa\Contracts\Core\Repository\Values\Translation; @@ -20,26 +21,23 @@ class Message extends Translation /** * Message string. Might use replacements like %foo%, which are replaced by * the values specified in the values array. - * - * @var string */ - protected $message; + protected string $message; /** * Translation value objects. May not contain any numbers, which might * result in requiring plural forms. Use Plural for that. * - * @var array + * @var array */ - protected $values; + protected array $values; /** * Construct singular only message from string and optional value array. * - * @param string $message - * @param array $values + * @param array $values */ - public function __construct($message, array $values = []) + public function __construct(string $message, array $values = []) { $this->message = $message; $this->values = $values; diff --git a/src/contracts/Repository/Values/Translation/Plural.php b/src/contracts/Repository/Values/Translation/Plural.php index f454cb315d..c5155d8668 100644 --- a/src/contracts/Repository/Values/Translation/Plural.php +++ b/src/contracts/Repository/Values/Translation/Plural.php @@ -4,6 +4,7 @@ * @copyright Copyright (C) Ibexa AS. All rights reserved. * @license For full copyright and license information view LICENSE file distributed with this source code. */ +declare(strict_types=1); namespace Ibexa\Contracts\Core\Repository\Values\Translation; @@ -12,58 +13,53 @@ /** * Class for translatable messages, which may contain plural forms. * - * The message might include replacements, in the form %[A-Za-z]%. Those are + * The message might include replacements, in the form %[A-Za-z]%. Those are * replaced by the values provided. A raw % can be escaped like %%. * * You need to provide a singular and plural variant for the string. The - * strings provided should be english and will be translated depending on the + * strings provided should be English and will be translated depending on the * environment language. * - * This interface follows the interfaces of XLiff, gettext, Symfony2 - * Translations and Zend_Translate. For singular forms you just provide a plain - * string (with optional placeholders without effects on the plural forms). For - * potential plural forms you always provide a singular variant and an english - * simple plural variant. No implementation supports multiple different plural - * forms in one single message. + * This interface follows the interfaces of XLIFF, gettext, Symfony Translations and Zend_Translate. + * For singular forms you just provide a plain string (with optional placeholders without effects on the plural forms). + * For potential plural forms you always provide a singular variant and an English simple plural variant. + * An instance of this class can be cast to a string. In such case whether to use singular or plural form is determined + * based on the value of first element of $values array (it needs to be 1 for singular, anything else for plural). + * If plurality cannot be inferred from $values, a plural form is assumed as default. To force singular form, + * use {@see \Ibexa\Contracts\Core\Repository\Values\Translation\Message} instead. * - * The singular / plural string could, for Symfony2, for example be converted - * to "$singular|$plural", and you would call gettext like: ngettext( - * $singular, $plural, $count ). + * No implementation supports multiple different plural forms in one single message. + * + * The singular / plural string could, for Symfony, for example be converted + * to "$singular|$plural", and you would call gettext like: ngettext($singular, $plural, $count ). */ class Plural extends Translation { /** * Singular string. Might use replacements like %foo%, which are replaced by * the values specified in the values array. - * - * @var string */ - protected $singular; + protected string $singular; /** * Message string. Might use replacements like %foo%, which are replaced by * the values specified in the values array. - * - * @var string */ - protected $plural; + protected string $plural; /** - * Translation value objects. May not contain any numbers, which might - * result in requiring plural forms. Use MessagePlural for that. + * Translation value objects. * - * @var array + * @var array */ - protected $values; + protected array $values; /** * Construct plural message from singular, plural and value array. * - * @param string $singular - * @param string $plural - * @param array $values + * @param array $values */ - public function __construct($singular, $plural, array $values) + public function __construct(string $singular, string $plural, array $values) { $this->singular = $singular; $this->plural = $plural; @@ -75,6 +71,8 @@ public function __construct($singular, $plural, array $values) #[\Override] public function __toString(): string { - return strtr(current($this->values) == 1 ? $this->plural : $this->singular, $this->values); + $firstValue = !empty($this->values) ? current(array_values($this->values)) : null; + + return strtr((int)$firstValue === 1 ? $this->singular : $this->plural, $this->values); } } diff --git a/tests/lib/Repository/Values/Translation/MessageTest.php b/tests/lib/Repository/Values/Translation/MessageTest.php new file mode 100644 index 0000000000..278847cb4b --- /dev/null +++ b/tests/lib/Repository/Values/Translation/MessageTest.php @@ -0,0 +1,61 @@ + + */ + public static function getDataForTestStringable(): iterable + { + yield 'message with substitution values' => [ + new Message( + 'Anna has some oranges in %object%', + [ + '%object%' => 'a basket', + ] + ), + 'Anna has some oranges in a basket', + ]; + + yield 'message with multiple substitution values' => [ + new Message( + '%first_name% has some data in %storage_type%', + [ + '%first_name%' => 'Anna', + '%storage_type%' => 'her database', + ] + ), + 'Anna has some data in her database', + ]; + + yield 'message with no substitution values' => [ + new Message( + 'This value is not correct', + [] + ), + 'This value is not correct', + ]; + } +} diff --git a/tests/lib/Repository/Values/Translation/PluralTest.php b/tests/lib/Repository/Values/Translation/PluralTest.php new file mode 100644 index 0000000000..d0d6e57f96 --- /dev/null +++ b/tests/lib/Repository/Values/Translation/PluralTest.php @@ -0,0 +1,63 @@ + + */ + public static function getDataForTestStringable(): iterable + { + yield 'singular form' => [ + new Plural( + 'John has %apple_count% apple', + 'John has %apple_count% apples', + [ + '%apple_count%' => 1, + ] + ), + 'John has 1 apple', + ]; + + yield 'plural form' => [ + new Plural( + 'John has %apple_count% apple', + 'John has %apple_count% apples', + [ + '%apple_count%' => 2, + ] + ), + 'John has 2 apples', + ]; + + yield 'no substitution values' => [ + new Plural( + 'John has some apples', + 'John has a lot of apples', + [] + ), + 'John has a lot of apples', + ]; + } +}