diff --git a/composer.json b/composer.json index c8d47a1ab..126b8864b 100755 --- a/composer.json +++ b/composer.json @@ -34,7 +34,8 @@ "illuminate/redis": "^13", "illuminate/reflection": "^13", "illuminate/session": "^13", - "illuminate/support": "^13", + "illuminate/support": "^13", + "illuminate/translation": "^13", "illuminate/view": "^13", "ircmaxell/password-compat": "~1.0", "laravel/serializable-closure": "^2.0.10", @@ -68,7 +69,6 @@ "illuminate/mail": "self.version", "illuminate/queue": "self.version", "illuminate/routing": "self.version", - "illuminate/translation": "self.version", "illuminate/validation": "self.version", "illuminate/workbench": "self.version" }, diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 583bcde59..1f6a3753c 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -214,6 +214,10 @@ public function bindInstallPaths(array $paths) { $this->instance("path.{$key}", realpath($value)); } + + // ponytail: v13 TranslationServiceProvider reads path.lang (absent from L4.2 install + // paths). Bind it here; remove once Foundation swaps to v13 (bootstrap sets langPath). + $this->instance('path.lang', $this['path'].'/lang'); } /** @@ -1233,6 +1237,19 @@ public function getLocale() return $this['config']->get('app.locale'); } + /** + * Get the current application fallback locale. + * + * ponytail: v13 TranslationServiceProvider calls getFallbackLocale(); the L4.2 fork + * Application lacks it. Remove once Foundation swaps to v13. + * + * @return string + */ + public function getFallbackLocale() + { + return $this['config']->get('app.fallback_locale'); + } + /** * Set the current application locale. * diff --git a/src/Illuminate/Validation/Factory.php b/src/Illuminate/Validation/Factory.php index 007b8ff6c..89c6f4b0b 100755 --- a/src/Illuminate/Validation/Factory.php +++ b/src/Illuminate/Validation/Factory.php @@ -2,7 +2,7 @@ use Closure; use Illuminate\Container\Container; -use Symfony\Contracts\Translation\TranslatorInterface; +use Illuminate\Contracts\Translation\Translator as TranslatorInterface; class Factory { diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index e5a48cedc..567626051 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -8,7 +8,7 @@ use Illuminate\Support\MessageBag; use Illuminate\Container\Container; use Symfony\Component\HttpFoundation\File\File; -use Symfony\Contracts\Translation\TranslatorInterface; +use Illuminate\Contracts\Translation\Translator as TranslatorInterface; use Symfony\Component\HttpFoundation\File\UploadedFile; use Illuminate\Support\Contracts\MessageProviderInterface; @@ -1511,7 +1511,7 @@ protected function getMessage($attribute, $rule) $customKey = "validation.custom.{$attribute}.{$lowerRule}"; - $customMessage = $this->translator->trans($customKey); + $customMessage = $this->translator->get($customKey); // First we check for a custom defined validation message for the attribute // and rule. This allows the developer to specify specific messages for @@ -1534,7 +1534,7 @@ protected function getMessage($attribute, $rule) // messages out of the translator service for this validation rule. $key = "validation.{$lowerRule}"; - if ($key != ($value = $this->translator->trans($key))) + if ($key != ($value = $this->translator->get($key))) { return $value; } @@ -1585,7 +1585,7 @@ protected function getSizeMessage($attribute, $rule) $key = "validation.{$lowerRule}.{$type}"; - return $this->translator->trans($key); + return $this->translator->get($key); } /** @@ -1682,7 +1682,7 @@ protected function getAttribute($attribute) // We allow for the developer to specify language lines for each of the // attributes allowing for more displayable counterparts of each of // the attributes. This provides the ability for simple formats. - if (($line = $this->translator->trans($key)) !== $key) + if (($line = $this->translator->get($key)) !== $key) { return $line; } @@ -1709,7 +1709,7 @@ public function getDisplayableValue($attribute, $value) $key = "validation.values.{$attribute}.{$value}"; - if (($line = $this->translator->trans($key)) !== $key) + if (($line = $this->translator->get($key)) !== $key) { return $line; } diff --git a/tests/Translation/TranslationFileLoaderTest.php b/tests/Translation/TranslationFileLoaderTest.php deleted file mode 100755 index f1697f814..000000000 --- a/tests/Translation/TranslationFileLoaderTest.php +++ /dev/null @@ -1,72 +0,0 @@ -shouldReceive('exists')->once()->with(__DIR__ . '/en/foo.php')->andReturn(true); - $files->shouldReceive('getRequire')->once()->with(__DIR__ . '/en/foo.php')->andReturn(['messages']); - - $this->assertEquals(['messages'], $loader->load('en', 'foo', null)); - } - - - public function testLoadMethodWithNamespacesProperlyCallsLoader() - { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); - $files->shouldReceive('exists')->once()->with('bar/en/foo.php')->andReturn(true); - $files->shouldReceive('exists')->once()->with(__DIR__.'/packages/en/namespace/foo.php')->andReturn(false); - $files->shouldReceive('getRequire')->once()->with('bar/en/foo.php')->andReturn(['foo' => 'bar']); - $loader->addNamespace('namespace', 'bar'); - - $this->assertEquals(['foo' => 'bar'], $loader->load('en', 'foo', 'namespace')); - } - - - public function testLoadMethodWithNamespacesProperlyCallsLoaderAndLoadsLocalOverrides() - { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); - $files->shouldReceive('exists')->once()->with('bar/en/foo.php')->andReturn(true); - $files->shouldReceive('exists')->once()->with(__DIR__.'/packages/en/namespace/foo.php')->andReturn(true); - $files->shouldReceive('getRequire')->once()->with('bar/en/foo.php')->andReturn(['foo' => 'bar']); - $files->shouldReceive('getRequire')->once()->with(__DIR__.'/packages/en/namespace/foo.php')->andReturn( - ['foo' => 'override', 'baz' => 'boom'] - ); - $loader->addNamespace('namespace', 'bar'); - - $this->assertEquals(['foo' => 'override', 'baz' => 'boom'], $loader->load('en', 'foo', 'namespace')); - } - - - public function testEmptyArraysReturnedWhenFilesDontExist() - { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); - $files->shouldReceive('exists')->once()->with(__DIR__.'/en/foo.php')->andReturn(false); - $files->shouldReceive('getRequire')->never(); - - $this->assertEquals([], $loader->load('en', 'foo', null)); - } - - - public function testEmptyArraysReturnedWhenFilesDontExistForNamespacedItems() - { - $loader = new FileLoader($files = m::mock(Filesystem::class), __DIR__); - $files->shouldReceive('getRequire')->never(); - - $this->assertEquals([], $loader->load('en', 'foo', 'bar')); - } - -} diff --git a/tests/Translation/TranslationTranslatorTest.php b/tests/Translation/TranslationTranslatorTest.php deleted file mode 100755 index 6d142b02f..000000000 --- a/tests/Translation/TranslationTranslatorTest.php +++ /dev/null @@ -1,206 +0,0 @@ -getMock(Translator::class, ['get'], [$this->getLoader(), 'en']); - $t->expects($this->once())->method('get')->with( - $this->equalTo('foo'), - $this->equalTo([]), - $this->equalTo('bar') - )->willReturn('foo'); - $this->assertFalse($t->has('foo', 'bar')); - - $t = $this->getMock(Translator::class, ['get'], [$this->getLoader(), 'en', 'sp']); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo([]), $this->equalTo('bar'))->willReturn( - 'bar' - ); - $this->assertTrue($t->has('foo', 'bar')); - } - - - public function testGetMethodProperlyLoadsAndRetrievesItem() - { - $t = $this->getMock(Translator::class, null, [$this->getLoader(), 'en'], '', true, true, true, false, true); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn( - ['foo' => 'foo', 'baz' => 'breeze :foo'] - ); - $this->assertEquals('breeze bar', $t->get('foo::bar.baz', ['foo' => 'bar'], 'en')); - $this->assertEquals('foo', $t->get('foo::bar.foo')); - } - - - public function testGetMethodProperlyLoadsAndRetrievesItemWithLongestReplacementsFirst() - { - $t = $this->getMock(Translator::class, null, [$this->getLoader(), 'en'], '', true, true, true, false, true); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'bar', 'foo')->andReturn( - ['foo' => 'foo', 'baz' => 'breeze :foo :foobar'] - ); - $this->assertEquals('breeze bar taylor', $t->get('foo::bar.baz', ['foo' => 'bar', 'foobar' => 'taylor'], 'en')); - $this->assertEquals('foo', $t->get('foo::bar.foo')); - } - - - public function testGetMethodProperlyLoadsAndRetrievesItemForGlobalNamespace() - { - $t = $this->getMock(Translator::class, null, [$this->getLoader(), 'en'], '', true, true, true, false, true); - $t->getLoader()->shouldReceive('load')->once()->with('en', 'foo', '*')->andReturn(['bar' => 'breeze :foo']); - $this->assertEquals('breeze bar', $t->get('foo.bar', ['foo' => 'bar'])); - } - - - public function testChoiceMethodProperlyLoadsAndRetrievesItem() - { - $t = $this->getMock(Translator::class, ['get'], [$this->getLoader(), 'en']); - $t->expects($this->once())->method('get')->with($this->equalTo('foo'), $this->equalTo(['replace']), $this->equalTo('en'))->willReturn( - 'line' - ); - $t->setSelector($selector = m::mock(MessageSelector::class)); - $selector->shouldReceive('choose')->once()->with('line', 10, 'en')->andReturn('choiced'); - - $t->choice('foo', 10, ['replace']); - } - - // TEST FROM SYMFONY - - /** - * @test - * @dataProvider getChooseTests - */ - public function choice($expected, $id, $number): void - { - $loader = $this->prophesize(LoaderInterface::class); - $translator = new Translator($loader->reveal(), 'en'); - $this->assertEquals($expected, $translator->choice($id, $number)); - } - - public function testReturnMessageIfExactlyOneStandardRuleIsGiven() - { - $loader = $this->prophesize(LoaderInterface::class); - $translator = new Translator($loader->reveal(), 'en'); - - $this->assertEquals('There are two apples', $translator->choice('There are two apples', 2)); - } - - /** - * @dataProvider getNonMatchingMessages - */ - public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number) - { - $this->expectException(InvalidArgumentException::class); - $loader = $this->prophesize(LoaderInterface::class); - $translator = new Translator($loader->reveal(), 'en'); - - $translator->choice($id, $number); - } - - protected function getLoader() - { - return m::mock(LoaderInterface::class); - } - - public function getNonMatchingMessages() - { - return [ - ['{0} There are no apples|{1} There is one apple', 2], - ['{1} There is one apple|]1,Inf] There are %count% apples', 0], - ['{1} There is one apple|]2,Inf] There are %count% apples', 2], - ['{0} There are no apples|There is one apple', 2], - ]; - } - - public function getChooseTests() - { - return [ - ['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0], - ['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0], - ['There are no apples', '{0}There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0], - - ['There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1], - - ['There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10], - ['There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf]There are %count% apples', 10], - ['There are %count% apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10], - - ['There are %count% apples', 'There is one apple|There are %count% apples', 0], - ['There is one apple', 'There is one apple|There are %count% apples', 1], - ['There are %count% apples', 'There is one apple|There are %count% apples', 10], - - ['There are %count% apples', 'one: There is one apple|more: There are %count% apples', 0], - ['There is one apple', 'one: There is one apple|more: There are %count% apples', 1], - ['There are %count% apples', 'one: There is one apple|more: There are %count% apples', 10], - - ['There are no apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 0], - ['There is one apple', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 1], - ['There are %count% apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 10], - - ['', '{0}|{1} There is one apple|]1,Inf] There are %count% apples', 0], - ['', '{0} There are no apples|{1}|]1,Inf] There are %count% apples', 1], - - // Indexed only tests which are Gettext PoFile* compatible strings. - ['There are %count% apples', 'There is one apple|There are %count% apples', 0], - ['There is one apple', 'There is one apple|There are %count% apples', 1], - ['There are %count% apples', 'There is one apple|There are %count% apples', 2], - - // Tests for float numbers - ['There is almost one apple', '{0} There are no apples|]0,1[ There is almost one apple|{1} There is one apple|[1,Inf] There is more than one apple', 0.7], - ['There is one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1], - ['There is more than one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1.7], - ['There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0], - ['There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0.0], - ['There are no apples', '{0.0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0], - - // Test texts with new-lines - // with double-quotes and \n in id & double-quotes and actual newlines in text - ["This is a text with a\n new-line in it. Selector = 0.", '{0}This is a text with a - new-line in it. Selector = 0.|{1}This is a text with a - new-line in it. Selector = 1.|[1,Inf]This is a text with a - new-line in it. Selector > 1.', 0], - // with double-quotes and \n in id and single-quotes and actual newlines in text - ["This is a text with a\n new-line in it. Selector = 1.", '{0}This is a text with a - new-line in it. Selector = 0.|{1}This is a text with a - new-line in it. Selector = 1.|[1,Inf]This is a text with a - new-line in it. Selector > 1.', 1], - ["This is a text with a\n new-line in it. Selector > 1.", '{0}This is a text with a - new-line in it. Selector = 0.|{1}This is a text with a - new-line in it. Selector = 1.|[1,Inf]This is a text with a - new-line in it. Selector > 1.', 5], - // with double-quotes and id split accros lines - ['This is a text with a - new-line in it. Selector = 1.', '{0}This is a text with a - new-line in it. Selector = 0.|{1}This is a text with a - new-line in it. Selector = 1.|[1,Inf]This is a text with a - new-line in it. Selector > 1.', 1], - // with single-quotes and id split accros lines - ['This is a text with a - new-line in it. Selector > 1.', '{0}This is a text with a - new-line in it. Selector = 0.|{1}This is a text with a - new-line in it. Selector = 1.|[1,Inf]This is a text with a - new-line in it. Selector > 1.', 5], - // with single-quotes and \n in text - ['This is a text with a\nnew-line in it. Selector = 0.', '{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.', 0], - // with double-quotes and id split accros lines - ["This is a text with a\nnew-line in it. Selector = 1.", "{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.", 1], - // esacape pipe - ['This is a text with | in it. Selector = 0.', '{0}This is a text with || in it. Selector = 0.|{1}This is a text with || in it. Selector = 1.', 0], - // Empty plural set (2 plural forms) from a .PO file - ['', '|', 1], - // Empty plural set (3 plural forms) from a .PO file - ['', '||', 1], - ]; - } -} diff --git a/tests/Validation/ValidationFactoryTest.php b/tests/Validation/ValidationFactoryTest.php index 53e19ba7e..0a2e762e7 100755 --- a/tests/Validation/ValidationFactoryTest.php +++ b/tests/Validation/ValidationFactoryTest.php @@ -7,7 +7,7 @@ class ValidationFactoryTest extends BackwardCompatibleTestCase { public function testMakeMethodCreatesValidValidator() { - $translator = $this->prophesize(Symfony\Contracts\Translation\TranslatorInterface::class); + $translator = $this->prophesize(Illuminate\Contracts\Translation\Translator::class); $factory = new Factory($translator->reveal()); $validator = $factory->make(['foo' => 'bar'], ['baz' => 'boom']); $this->assertEquals($translator->reveal(), $validator->getTranslator()); @@ -41,7 +41,7 @@ public function testMakeMethodCreatesValidValidator() public function testCustomResolverIsCalled() { unset($_SERVER['__validator.factory']); - $translator = $this->prophesize(Symfony\Contracts\Translation\TranslatorInterface::class); + $translator = $this->prophesize(Illuminate\Contracts\Translation\Translator::class); $factory = new Factory($translator->reveal()); $factory->resolver(function($translator, $data, $rules) { diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index efd2865bb..f66ee0a8d 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -7,7 +7,7 @@ use Mockery as m; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; -use Symfony\Contracts\Translation\TranslatorInterface; +use Illuminate\Contracts\Translation\Translator as TranslatorInterface; class ValidationValidatorTest extends BackwardCompatibleTestCase { @@ -61,7 +61,7 @@ public function testHasFailedValidationRules() public function testHasNotFailedValidationRules() { $trans = $this->getTranslator(); - $trans->shouldReceive('trans')->never(); + $trans->shouldReceive('get')->never(); $v = new Validator($trans, ['foo' => 'taylor'], ['name' => 'Confirmed']); $this->assertTrue($v->passes()); $this->assertEmpty($v->failed()); @@ -71,7 +71,7 @@ public function testHasNotFailedValidationRules() public function testSometimesCanSkipRequiredRules() { $trans = $this->getTranslator(); - $trans->shouldReceive('trans')->never(); + $trans->shouldReceive('get')->never(); $v = new Validator($trans, [], ['name' => 'sometimes|required']); $this->assertTrue($v->passes()); $this->assertEmpty($v->failed()); @@ -81,7 +81,7 @@ public function testSometimesCanSkipRequiredRules() public function testInValidatableRulesReturnsValid() { $trans = $this->getTranslator(); - $trans->shouldReceive('trans')->never(); + $trans->shouldReceive('get')->never(); $v = new Validator($trans, ['foo' => 'taylor'], ['name' => 'Confirmed']); $this->assertTrue($v->passes()); } @@ -1438,9 +1438,13 @@ protected function getTranslator() protected function getRealTranslator() { - $trans = new Symfony\Component\Translation\Translator('en'); - $trans->addLoader('array', new Symfony\Component\Translation\Loader\ArrayLoader); - return $trans; + // v13 Translator; shim addResource() (Symfony API these tests use) onto addLines(). + return new class(new \Illuminate\Translation\ArrayLoader, 'en') extends \Illuminate\Translation\Translator { + public function addResource($format, array $messages, $locale, $domain = 'messages'): void + { + $this->addLines($messages, $locale); + } + }; } }