diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/translations2/ccc.fr.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/translations2/ccc.fr.yml new file mode 100644 index 0000000000..20e9ff3fea --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/translations2/ccc.fr.yml @@ -0,0 +1 @@ +foo: bar diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php index 0c243222ae..9f85b18d01 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Config\Resource\DirectoryResource; use Symfony\Component\Config\Resource\FileExistenceResource; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Translation\Formatter\MessageFormatter; +use Symfony\Component\Translation\Loader\YamlFileLoader; use Symfony\Component\Translation\MessageCatalogue; class TranslatorTest extends TestCase @@ -244,6 +245,41 @@ class TranslatorTest extends TestCase $this->assertEquals(new FileExistenceResource('/tmp/I/sure/hope/this/does/not/exist'), $resources[2]); } + public function testCachedCatalogueIsReDumpedWhenScannedDirectoriesChange() + { + /** @var Translator $translator */ + $translator = $this->getTranslator(new YamlFileLoader(), [ + 'cache_dir' => $this->tmpDir, + 'resource_files' => [ + 'fr' => [ + __DIR__.'/../Fixtures/Resources/translations/messages.fr.yml', + ], + ], + 'scanned_directories' => [ + __DIR__.'/../Fixtures/Resources/translations/', + ], + ], 'yml'); + + // Cached catalogue is dumped + $this->assertSame('répertoire', $translator->trans('folder', [], 'messages', 'fr')); + + $translator = $this->getTranslator(new YamlFileLoader(), [ + 'cache_dir' => $this->tmpDir, + 'resource_files' => [ + 'fr' => [ + __DIR__.'/../Fixtures/Resources/translations/messages.fr.yml', + __DIR__.'/../Fixtures/Resources/translations2/ccc.fr.yml', + ], + ], + 'scanned_directories' => [ + __DIR__.'/../Fixtures/Resources/translations/', + __DIR__.'/../Fixtures/Resources/translations2/', + ], + ], 'yml'); + + $this->assertSame('bar', $translator->trans('foo', [], 'ccc', 'fr')); + } + protected function getCatalogue($locale, $messages, $resources = []) { $catalogue = new MessageCatalogue($locale); diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php index 721c020370..95d9ce564c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php @@ -82,7 +82,9 @@ class Translator extends BaseTranslator implements WarmableInterface $this->resourceFiles = $this->options['resource_files']; $this->scannedDirectories = $this->options['scanned_directories']; - parent::__construct($defaultLocale, $formatter, $this->options['cache_dir'], $this->options['debug']); + parent::__construct($defaultLocale, $formatter, $this->options['cache_dir'], $this->options['debug'], [ + 'scanned_directories' => $this->scannedDirectories, + ]); } /** diff --git a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php index 25d2725ed4..75b14c6b73 100644 --- a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php +++ b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php @@ -147,7 +147,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface throw $previous; } - $e = new \ReflectionException("Class $class not found", 0, $previous); + $e = new \ReflectionException(sprintf('Class "%s" not found while loading "%s".', $class, self::$autoloadedClass), 0, $previous); if (null !== $previous) { throw $e; diff --git a/src/Symfony/Component/Config/Tests/Resource/ClassExistenceResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/ClassExistenceResourceTest.php index ad331240de..b7ae81eaa6 100644 --- a/src/Symfony/Component/Config/Tests/Resource/ClassExistenceResourceTest.php +++ b/src/Symfony/Component/Config/Tests/Resource/ClassExistenceResourceTest.php @@ -84,7 +84,7 @@ EOF public function testBadParentWithNoTimestamp() { $this->expectException('ReflectionException'); - $this->expectExceptionMessage('Class Symfony\Component\Config\Tests\Fixtures\MissingParent not found'); + $this->expectExceptionMessage('Class "Symfony\Component\Config\Tests\Fixtures\MissingParent" not found while loading "Symfony\Component\Config\Tests\Fixtures\BadParent".'); $res = new ClassExistenceResource(BadParent::class, false); $res->isFresh(0); diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 19f41d9965..247a021fd7 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -343,7 +343,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface return null; } - $resource = null; + $resource = $classReflector = null; try { if (isset($this->classReflectors[$class])) { @@ -358,7 +358,6 @@ class ContainerBuilder extends Container implements TaggedContainerInterface if ($throw) { throw $e; } - $classReflector = false; } if ($this->trackResources) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php index ceb0f0113e..12c7e70948 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php @@ -156,12 +156,7 @@ abstract class FileLoader extends BaseFileLoader try { $r = $this->container->getReflectionClass($class); } catch (\ReflectionException $e) { - $classes[$class] = sprintf( - 'While discovering services from namespace "%s", an error was thrown when processing the class "%s": "%s".', - $namespace, - $class, - $e->getMessage() - ); + $classes[$class] = $e->getMessage(); continue; } // check to make sure the expected class exists diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 2110f02171..e036059f53 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -363,7 +363,7 @@ class AutowirePassTest extends TestCase $pass->process($container); $this->fail('AutowirePass should have thrown an exception'); } catch (AutowiringFailedException $e) { - $this->assertSame('Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class is missing a parent class (Class Symfony\Bug\NotExistClass not found).', (string) $e->getMessage()); + $this->assertRegExp('{^Cannot autowire service "a": argument "\$r" of method "(Symfony\\\\Component\\\\DependencyInjection\\\\Tests\\\\Compiler\\\\)BadParentTypeHintedArgument::__construct\(\)" has type "\1OptionalServiceClass" but this class is missing a parent class \(Class "?Symfony\\\\Bug\\\\NotExistClass"? not found}', (string) $e->getMessage()); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php index ae620a48d5..b9ea798d2c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php @@ -196,9 +196,9 @@ class FileLoaderTest extends TestCase $this->assertTrue($container->has(MissingParent::class)); - $this->assertSame( - ['While discovering services from namespace "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\", an error was thrown when processing the class "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\MissingParent": "Class Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\MissingClass not found".'], - $container->getDefinition(MissingParent::class)->getErrors() + $this->assertRegExp( + '{Class "?Symfony\\\\Component\\\\DependencyInjection\\\\Tests\\\\Fixtures\\\\Prototype\\\\BadClasses\\\\MissingClass"? not found}', + $container->getDefinition(MissingParent::class)->getErrors()[0] ); } diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 6120fb8d04..5e9fe4221b 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -327,15 +327,20 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface public function __destruct() { $this->multi->pushedResponses = []; - if (\defined('CURLMOPT_PUSHFUNCTION')) { - curl_multi_setopt($this->multi->handle, CURLMOPT_PUSHFUNCTION, null); + + if (\is_resource($this->multi->handle)) { + if (\defined('CURLMOPT_PUSHFUNCTION')) { + curl_multi_setopt($this->multi->handle, CURLMOPT_PUSHFUNCTION, null); + } + + $active = 0; + while (CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active)); } - $active = 0; - while (CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active)); - foreach ($this->multi->openHandles as [$ch]) { - curl_setopt($ch, CURLOPT_VERBOSE, false); + if (\is_resource($ch)) { + curl_setopt($ch, CURLOPT_VERBOSE, false); + } } } diff --git a/src/Symfony/Component/Translation/Tests/TranslatorCacheTest.php b/src/Symfony/Component/Translation/Tests/TranslatorCacheTest.php index 149a15fce2..8efa318cac 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorCacheTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorCacheTest.php @@ -269,6 +269,22 @@ class TranslatorCacheTest extends TestCase $translator->trans('foo'); } + public function testCachedCatalogueIsReDumpedWhenCacheVaryChange() + { + $translator = new Translator('a', null, $this->tmpDir, false, []); + $translator->addLoader('array', new ArrayLoader()); + $translator->addResource('array', ['foo' => 'bar'], 'a', 'messages'); + + // Cached catalogue is dumped + $this->assertSame('bar', $translator->trans('foo', [], 'messages', 'a')); + + $translator = new Translator('a', null, $this->tmpDir, false, ['vary']); + $translator->addLoader('array', new ArrayLoader()); + $translator->addResource('array', ['foo' => 'ccc'], 'a', 'messages'); + + $this->assertSame('ccc', $translator->trans('foo', [], 'messages', 'a')); + } + protected function getCatalogue($locale, $messages, $resources = []) { $catalogue = new MessageCatalogue($locale); diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index bb36ee184c..4e413da7a8 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -71,6 +71,8 @@ class Translator implements LegacyTranslatorInterface, TranslatorInterface, Tran */ private $debug; + private $cacheVary; + /** * @var ConfigCacheFactoryInterface|null */ @@ -86,7 +88,7 @@ class Translator implements LegacyTranslatorInterface, TranslatorInterface, Tran /** * @throws InvalidArgumentException If a locale contains invalid characters */ - public function __construct(?string $locale, MessageFormatterInterface $formatter = null, string $cacheDir = null, bool $debug = false) + public function __construct(?string $locale, MessageFormatterInterface $formatter = null, string $cacheDir = null, bool $debug = false, array $cacheVary = []) { if (null === $locale) { @trigger_error(sprintf('Passing "null" as the $locale argument to %s() is deprecated since Symfony 4.4.', __METHOD__), E_USER_DEPRECATED); @@ -101,6 +103,7 @@ class Translator implements LegacyTranslatorInterface, TranslatorInterface, Tran $this->formatter = $formatter; $this->cacheDir = $cacheDir; $this->debug = $debug; + $this->cacheVary = $cacheVary; $this->hasIntlFormatter = $formatter instanceof IntlFormatterInterface; } @@ -190,7 +193,7 @@ class Translator implements LegacyTranslatorInterface, TranslatorInterface, Tran $this->assertValidLocale($locale); } - $this->fallbackLocales = $locales; + $this->fallbackLocales = $this->cacheVary['fallback_locales'] = $locales; } /** @@ -412,7 +415,7 @@ EOF private function getCatalogueCachePath(string $locale): string { - return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('sha256', serialize($this->fallbackLocales), true)), 0, 7), '/', '_').'.php'; + return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('sha256', serialize($this->cacheVary), true)), 0, 7), '/', '_').'.php'; } /** diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf index 6510514900..6f9ab0a1cf 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf @@ -72,7 +72,7 @@ This value should be {{ limit }} or less. - הערך צריל להכיל {{ limit }} תווים לכל היותר. + הערך צריך להכיל {{ limit }} תווים לכל היותר. This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. @@ -84,7 +84,7 @@ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - הערך קצר מידיץ הוא צריך להכיל {{ limit }} תווים לפחות.|הערך קצר מידיץ הוא צריך להכיל {{ limit }} תווים לפחות. + הערך קצר מידי. הוא צריך להכיל {{ limit }} תווים לפחות.|הערך קצר מידיץ הוא צריך להכיל {{ limit }} תווים לפחות. This value should not be blank. @@ -224,83 +224,147 @@ This is not a valid International Bank Account Number (IBAN). - This is not a valid International Bank Account Number (IBAN). + מספר חשבון בנק בינלאומי אינו חוקי (IBAN). This value is not a valid ISBN-10. - This value is not a valid ISBN-10. + הערך אינו ערך ISBN-10 חוקי. This value is not a valid ISBN-13. - This value is not a valid ISBN-13. + הערך אינו ערך ISBN-13 חוקי. This value is neither a valid ISBN-10 nor a valid ISBN-13. - This value is neither a valid ISBN-10 nor a valid ISBN-13. + הערך אינו ערך ISBN-10 חוקי או ערך ISBN-13 חוקי. This value is not a valid ISSN. - This value is not a valid ISSN. + הערך אינו ערך ISSN חוקי. This value is not a valid currency. - This value is not a valid currency. + הערך אינו ערך מטבע חוקי. This value should be equal to {{ compared_value }}. - This value should be equal to {{ compared_value }}. + הערך חייב להיות שווה ל {{ compared_value }}. This value should be greater than {{ compared_value }}. - This value should be greater than {{ compared_value }}. + הערך חייב להיות גדול מ {{ compared_value }}. This value should be greater than or equal to {{ compared_value }}. - This value should be greater than or equal to {{ compared_value }}. + הערך חייב להיות גדול או שווה ל {{ compared_value }}. This value should be identical to {{ compared_value_type }} {{ compared_value }}. - This value should be identical to {{ compared_value_type }} {{ compared_value }}. + הערך חייב להיות זהה ל {{ compared_value_type }} {{ compared_value }}. This value should be less than {{ compared_value }}. - This value should be less than {{ compared_value }}. + הערך חייב להיות קטן מ {{ compared_value }}. This value should be less than or equal to {{ compared_value }}. - This value should be less than or equal to {{ compared_value }}. + הערך חייב להיות קטן או שווה ל {{ compared_value }}. This value should not be equal to {{ compared_value }}. - This value should not be equal to {{ compared_value }}. + הערך חייב להיות לא שווה ל {{ compared_value }}. This value should not be identical to {{ compared_value_type }} {{ compared_value }}. - This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + הערך חייב להיות לא זהה ל {{ compared_value_type }} {{ compared_value }}. The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. - The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + היחס של התמונה הוא גדול מדי ({{ ratio }}). היחס המקסימלי האפשרי הוא {{ max_ratio }}. The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. - The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + היחס של התמונה הוא קטן מדי ({{ ratio }}). היחס המינימלי האפשרי הוא {{ min_ratio }}. The image is square ({{ width }}x{{ height }}px). Square images are not allowed. - The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + התמונה מרובעת ({{ width }}x{{ height }}px). אסורות תמונות מרובעות. The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. - The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + התמונה היא לרוחב ({{ width }}x{{ height }}px). אסורות תמונות לרוחב. The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. - The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + התמונה היא לאורך ({{ width }}x{{ height }}px). אסורות תמונות לאורך. An empty file is not allowed. - An empty file is not allowed. + אסור קובץ ריק. + + + The host could not be resolved. + לא הייתה אפשרות לזהות את המארח. + + + This value does not match the expected {{ charset }} charset. + הערך אינו תואם למערך התווים {{ charset }} הצפוי. + + + This is not a valid Business Identifier Code (BIC). + קוד זיהוי עסקי אינו חוקי (BIC). + + + Error + שגיאה + + + This is not a valid UUID. + הערך אינו ערך UUID חוקי. + + + This value should be a multiple of {{ compared_value }}. + הערך חייב להיות כפולה של {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + הקוד זיהוי עסקי (BIC) אינו משוייך ל IBAN {{ iban }}. + + + This value should be valid JSON. + הערך אינו ערך JSON תקין. + + + This collection should contain only unique elements. + האוסף חייב להכיל רק אלמנטים ייחודיים. + + + This value should be positive. + הערך חייב להיות חיובי. + + + This value should be either positive or zero. + הערך חייב להיות חיובי או אפס. + + + This value should be negative. + הערך חייב להיות שלילי. + + + This value should be either negative or zero. + הערך חייב להיות שלילי או אפס. + + + This value is not a valid timezone. + הערך אינו אזור זמן תקין. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + סיסמא זו הודלפה בהדלפת מידע, אסור להשתמש בה. אנא השתמש בסיסמה אחרת. + + + This value should be between {{ min }} and {{ max }}. + הערך חייב להיות בין {{ min }} ו- {{ max }}.