diff --git a/.gitattributes b/.gitattributes index a1bf466..773a14a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,12 @@ +* text=auto + +/.github export-ignore /_docs export-ignore /tests export-ignore -/.editorconfig export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.scrutinizer.yml export-ignore -/.travis.yml export-ignore -/phpunit.xml export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.scrutinizer.yml export-ignore +.travis.yml export-ignore +phpunit.xml export-ignore +CONTRIBUTING.md export-ignore diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..4e96585 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,7 @@ +- Localization Version: #.#.# +- Laravel Version: #.#.# +- PHP Version: #.#.# + +### Description: + +### Steps To Reproduce: diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 4b1692f..282131b 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -21,8 +21,8 @@ checks: tools: external_code_coverage: - timeout: 1800 - runs: 8 + timeout: 600 + runs: 3 php_code_sniffer: enabled: true config: diff --git a/.travis.yml b/.travis.yml index 378d088..5c475de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,14 +13,11 @@ matrix: - php: nightly env: - - TESTBENCH_VERSION=3.0.* - - TESTBENCH_VERSION=3.1.* - - TESTBENCH_VERSION=3.2.* - - TESTBENCH_VERSION=3.3.* + - TESTBENCH_VERSION=3.4.* before_script: - travis_retry composer self-update - - travis_retry composer require --prefer-source --no-interaction --dev "orchestra/testbench:${TESTBENCH_VERSION}" + - travis_retry composer require --prefer-source --no-interaction --dev "orchestra/testbench-browser-kit:${TESTBENCH_VERSION}" "orchestra/database:${TESTBENCH_VERSION}" script: - composer validate diff --git a/LICENSE.md b/LICENSE.md index 84f2321..5f29328 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015-2016 | ARCANEDEV - Localization +Copyright (c) 2015-2017 | ARCANEDEV - Localization Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 6b924c5..c1f8a8e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Feel free to check out the [releases](https://github.com/ARCANEDEV/Localization/ ### Features * Easy setup & configuration. - * Laravel `5.0 | 5.1 | 5.2 | 5.3` are supported. + * Laravel `5.0 | 5.1 | 5.2 | 5.3 | 5.4` are supported. * SEO-Friendly (Search engine optimization). * New extended Router to manage your localized routes. * Locales selector menu (Publishable & Customizable). diff --git a/composer.json b/composer.json index 4079bf1..41c9ee9 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "type": "library", "license": "MIT", "require": { - "php" : ">=5.6.4", + "php": ">=5.6.4", "arcanedev/support": "~3.20" }, "require-dev": { @@ -33,7 +33,7 @@ } }, "scripts": { - "testbench": "composer require --dev \"orchestra/testbench=~3.0\"" + "testbench": "composer require --dev \"orchestra/testbench-browser-kit=~3.4\" \"orchestra/database=~3.4\"" }, "suggest": { "ext-intl": "Use Intl extension for 'Locale' class (an identifier used to get language)." @@ -42,5 +42,7 @@ "branch-alias": { "dev-master": "1.0.x-dev" } - } + }, + "minimum-stability": "dev", + "prefer-stable" : true } diff --git a/phpunit.xml b/phpunit.xml index 844ff0b..a3882c8 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -20,6 +20,9 @@ ./src/ + + + diff --git a/src/Bases/Middleware.php b/src/Bases/Middleware.php index 556016b..df5c617 100644 --- a/src/Bases/Middleware.php +++ b/src/Bases/Middleware.php @@ -13,6 +13,17 @@ */ abstract class Middleware extends BaseMiddleware { + /* ------------------------------------------------------------------------------------------------ + | Properties + | ------------------------------------------------------------------------------------------------ + */ + /** + * The URIs that should not be localized. + * + * @var array + */ + protected $except = []; + /* ------------------------------------------------------------------------------------------------ | Getters & Setters | ------------------------------------------------------------------------------------------------ @@ -75,6 +86,26 @@ protected function isDefaultLocaleHidden($locale) return $this->getDefaultLocale() === $locale && $this->hideDefaultLocaleInURL(); } + /** + * Determine if the request has a URI that should not be localized. + * + * @param \Illuminate\Http\Request $request + * + * @return bool + */ + protected function shouldIgnore($request) + { + foreach ($this->except as $except) { + if ($except !== '/') + $except = trim($except, '/'); + + if ($request->is($except)) + return true; + } + + return false; + } + /* ------------------------------------------------------------------------------------------------ | Other Functions | ------------------------------------------------------------------------------------------------ diff --git a/src/Middleware/LocaleCookieRedirect.php b/src/Middleware/LocaleCookieRedirect.php index 63b7411..0108c69 100644 --- a/src/Middleware/LocaleCookieRedirect.php +++ b/src/Middleware/LocaleCookieRedirect.php @@ -28,6 +28,10 @@ class LocaleCookieRedirect extends Middleware */ public function handle(Request $request, Closure $next) { + // If the request URL is ignored from localization. + if ($this->shouldIgnore($request)) + return $next($request); + $segment = $request->segment(1, null); $locale = $request->cookie('locale', null); diff --git a/src/Middleware/LocaleSessionRedirect.php b/src/Middleware/LocaleSessionRedirect.php index ff4730d..8da818f 100644 --- a/src/Middleware/LocaleSessionRedirect.php +++ b/src/Middleware/LocaleSessionRedirect.php @@ -28,6 +28,10 @@ class LocaleSessionRedirect extends Middleware */ public function handle(Request $request, Closure $next) { + // If the request URL is ignored from localization. + if ($this->shouldIgnore($request)) + return $next($request); + $segment = $request->segment(1, null); $locale = session('locale', null); diff --git a/src/Middleware/LocalizationRedirect.php b/src/Middleware/LocalizationRedirect.php index 49737ae..4c58bb8 100644 --- a/src/Middleware/LocalizationRedirect.php +++ b/src/Middleware/LocalizationRedirect.php @@ -28,6 +28,10 @@ class LocalizationRedirect extends Middleware */ public function handle(Request $request, Closure $next) { + // If the request URL is ignored from localization. + if ($this->shouldIgnore($request)) + return $next($request); + if ($redirectUrl = $this->getRedirectionUrl($request)) { // Save any flashed data for redirect session()->reflash(); diff --git a/src/Middleware/LocalizationRoutes.php b/src/Middleware/LocalizationRoutes.php index 57e3090..d8174be 100644 --- a/src/Middleware/LocalizationRoutes.php +++ b/src/Middleware/LocalizationRoutes.php @@ -26,6 +26,10 @@ class LocalizationRoutes extends Middleware */ public function handle(Request $request, Closure $next) { + // If the request URL is ignored from localization. + if ($this->shouldIgnore($request)) + return $next($request); + localization()->setRouteNameFromRequest($request); return $next($request); diff --git a/src/Middleware/TranslationRedirect.php b/src/Middleware/TranslationRedirect.php index 0ec00b2..c4981f4 100644 --- a/src/Middleware/TranslationRedirect.php +++ b/src/Middleware/TranslationRedirect.php @@ -33,6 +33,10 @@ class TranslationRedirect extends Middleware */ public function handle(Request $request, Closure $next) { + // If the request URL is ignored from localization. + if ($this->shouldIgnore($request)) + return $next($request); + $translatedUrl = $this->getTranslatedUrl($request); if ( ! is_null($translatedUrl)) { diff --git a/src/Providers/RoutingServiceProvider.php b/src/Providers/RoutingServiceProvider.php index 05be69b..4cd87c4 100644 --- a/src/Providers/RoutingServiceProvider.php +++ b/src/Providers/RoutingServiceProvider.php @@ -82,7 +82,7 @@ private function registerMiddlewares() */ private function registerMiddleware(Router $router, $name, $class) { - $router->middleware($name, $class); + $router->aliasMiddleware($name, $class); if ($this->getMiddleware($name)) { $this->middleware[] = $name; diff --git a/src/Routing/ResourceRegistrar.php b/src/Routing/ResourceRegistrar.php deleted file mode 100644 index d07a738..0000000 --- a/src/Routing/ResourceRegistrar.php +++ /dev/null @@ -1,37 +0,0 @@ - - */ -class ResourceRegistrar extends IlluminateResourceRegistrar -{ - /* ------------------------------------------------------------------------------------------------ - | Main Functions - | ------------------------------------------------------------------------------------------------ - */ - /** - * Get the resource name for a grouped resource. - * - * @param string $prefix - * @param string $resource - * @param string $method - * @return string - */ - protected function getGroupResourceName($prefix, $resource, $method) - { - $currentLocale = localization()->getCurrentLocale(); - $group = trim(str_replace('/', '.', $this->router->getLastGroupPrefix()), '.'); - $group = str_replace($currentLocale . '.', '', $group); - - if ( ! empty($group) && $group !== $currentLocale) { - return trim("{$prefix}{$group}.{$resource}.{$method}", '.'); - } - - return trim("{$prefix}{$resource}.{$method}", '.'); - } -} diff --git a/src/Routing/Router.php b/src/Routing/Router.php index 0bc7894..befbfc1 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -27,22 +27,6 @@ protected function getActiveMiddlewares() )); } - /* ------------------------------------------------------------------------------------------------ - | Basic Route Functions - | ------------------------------------------------------------------------------------------------ - */ - /** - * Route a resource to a controller. - * - * @param string $name - * @param string $controller - * @param array $options - */ - public function resource($name, $controller, array $options = []) - { - (new ResourceRegistrar($this))->register($name, $controller, $options); - } - /* ------------------------------------------------------------------------------------------------ | Route Functions | ------------------------------------------------------------------------------------------------ diff --git a/src/Utilities/Negotiator.php b/src/Utilities/Negotiator.php index 267dbb4..18dc21f 100644 --- a/src/Utilities/Negotiator.php +++ b/src/Utilities/Negotiator.php @@ -174,6 +174,13 @@ private function inSupportedLocales(array $matches) foreach (array_keys($matches) as $locale) { if ($this->isSupported($locale)) return $locale; + + // Search for acceptable locale by 'regional' => 'fr_FR' match. + foreach ($this->supportedLocales as $key => $entity) { + /** @var \Arcanedev\Localization\Entities\Locale $entity */ + if ($entity->regional() == $locale) + return $key; + } } return null; diff --git a/src/Utilities/RouteTranslator.php b/src/Utilities/RouteTranslator.php index c7f2850..3466f0d 100644 --- a/src/Utilities/RouteTranslator.php +++ b/src/Utilities/RouteTranslator.php @@ -241,7 +241,7 @@ private function translate($key, $locale = null) $locale = $this->translator->getLocale(); } - $translation = $this->translator->trans($key, [], '', $locale); + $translation = $this->translator->trans($key, [], $locale); // @codeCoverageIgnoreStart if ( ! is_string($translation)) { diff --git a/src/Utilities/Url.php b/src/Utilities/Url.php index b4eaa99..ea30f89 100644 --- a/src/Utilities/Url.php +++ b/src/Utilities/Url.php @@ -110,7 +110,7 @@ private static function extractAttributesFromRoutes($url, $routes) continue; } - $match = self::hasAttributesFromUriPath($url, $route->getUri(), $attributes); + $match = self::hasAttributesFromUriPath($url, $route->uri(), $attributes); if ($match) break; diff --git a/tests/Stubs/Http/Kernel.php b/tests/Stubs/Http/Kernel.php index 8d1bb58..35974e3 100644 --- a/tests/Stubs/Http/Kernel.php +++ b/tests/Stubs/Http/Kernel.php @@ -21,6 +21,21 @@ class Kernel extends HttpKernel | Properties | ------------------------------------------------------------------------------------------------ */ + /** + * The application's route middleware groups. + * + * @var array + */ + protected $middlewareGroups = [ + 'web' => [ + Middleware\EncryptCookies::class, + \Illuminate\Session\Middleware\StartSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \Orchestra\Testbench\Http\Middleware\VerifyCsrfToken::class, + \Illuminate\Routing\Middleware\SubstituteBindings::class, + ], + ]; + /** * The application's route middleware. * diff --git a/tests/Stubs/Http/Middleware/EncryptCookies.php b/tests/Stubs/Http/Middleware/EncryptCookies.php new file mode 100644 index 0000000..27d36a4 --- /dev/null +++ b/tests/Stubs/Http/Middleware/EncryptCookies.php @@ -0,0 +1,21 @@ + + */ +class EncryptCookies extends BaseEncrypter +{ + /** + * The names of the cookies that should not be encrypted. + * + * @var array + */ + protected $except = [ + 'locale' + ]; +} diff --git a/tests/Stubs/Http/RouteRegistrar.php b/tests/Stubs/Http/RouteRegistrar.php index 7466f0a..31e353b 100644 --- a/tests/Stubs/Http/RouteRegistrar.php +++ b/tests/Stubs/Http/RouteRegistrar.php @@ -91,126 +91,129 @@ public function map(Router $router) { $this->setRouter($router); - $this->router->localizedGroup(function () { - $this->router->get('/', [ - 'as' => 'index', - function () { - return app('translator')->get('localization::routes.hello'); - } - ]); - $this->setRouteName('index'); - - $this->router->get('test', [ - 'as' => 'test', - function () { - return app('translator')->get('localization::routes.test-text'); - } - ]); - $this->setRouteName('test'); - - $this->router->transGet('localization::routes.about', [ - 'as' => 'about', - function () { - return localization()->getLocalizedURL('es') ?: 'Not url available'; - } - ]); - $this->setRouteName('about'); - - $this->router->transGet('localization::routes.view', [ - 'as' => 'view', - function () { - return localization()->getLocalizedURL('es') ?: 'Not url available'; - } - ]); - $this->setRouteName('view'); - - $this->router->transGet('localization::routes.view-project', [ - 'as' => 'view-project', - function () { - return localization()->getLocalizedURL('es') ?: 'Not url available'; - } - ]); - $this->setRouteName('view-project'); - - /* ------------------------------------------------------------------------------------------------ - | Other method - | ------------------------------------------------------------------------------------------------ - */ - $this->router->transPost('localization::routes.methods.post', [ - 'as' => 'method.post', - function () { - return 'POST method'; - } - ]); - $this->setRouteName('method.post'); - - $this->router->transPut('localization::routes.methods.put', [ - 'as' => 'method.put', - function () { - return 'PUT method'; - } - ]); - $this->setRouteName('method.put'); - - $this->router->transPatch('localization::routes.methods.patch', [ - 'as' => 'method.patch', - function () { - return 'PATCH method'; - } - ]); - $this->setRouteName('method.patch'); - - $this->router->transOptions('localization::routes.methods.options', [ - 'as' => 'method.options', - function () { - return 'OPTIONS method'; - } - ]); - $this->setRouteName('method.options'); - - $this->router->transDelete('localization::routes.methods.delete', [ - 'as' => 'method.delete', - function () { - return 'DELETE method'; - } - ]); - $this->setRouteName('method.delete'); - - $this->router->transAny('localization::routes.methods.any', [ - 'as' => 'method.any', - function () { - return 'Any method'; - } - ]); - $this->setRouteName('method.any'); - - /* ------------------------------------------------------------------------------------------------ - | Resource Controller - | ------------------------------------------------------------------------------------------------ - */ - $this->router->resource('dummy', Controllers\DummyController::class); - $this->setRouteNames([ - 'dummy.index', - 'dummy.create', - 'dummy.store', - 'dummy.show', - 'dummy.edit', - 'dummy.update', - 'dummy.destroy', - ]); - - $this->router->group(['prefix' => 'foo'], function () { - $this->router->resource('bar', Controllers\BarController::class); + $this->router->group(['middleware' => 'web'], function () { + $this->router->localizedGroup(function () { + $this->router->get('/', [ + 'as' => 'index', + function () { + return app('translator')->get('localization::routes.hello'); + } + ]); + $this->setRouteName('index'); + + $this->router->get('test', [ + 'as' => 'test', + function () { + return app('translator')->get('localization::routes.test-text'); + } + ]); + $this->setRouteName('test'); + + $this->router->transGet('localization::routes.about', [ + 'as' => 'about', + function () { + return localization()->getLocalizedURL('es') ?: 'Not url available'; + } + ]); + $this->setRouteName('about'); + + $this->router->transGet('localization::routes.view', [ + 'as' => 'view', + function () { + return localization()->getLocalizedURL('es') ?: 'Not url available'; + } + ]); + $this->setRouteName('view'); + + $this->router->transGet('localization::routes.view-project', [ + 'as' => 'view-project', + function () { + return localization()->getLocalizedURL('es') ?: 'Not url available'; + } + ]); + $this->setRouteName('view-project'); + + /* ------------------------------------------------------------------------------------------------ + | Other method + | ------------------------------------------------------------------------------------------------ + */ + $this->router->transPost('localization::routes.methods.post', [ + 'as' => 'method.post', + function () { + return 'POST method'; + } + ]); + $this->setRouteName('method.post'); + + $this->router->transPut('localization::routes.methods.put', [ + 'as' => 'method.put', + function () { + return 'PUT method'; + } + ]); + $this->setRouteName('method.put'); + + $this->router->transPatch('localization::routes.methods.patch', [ + 'as' => 'method.patch', + function () { + return 'PATCH method'; + } + ]); + $this->setRouteName('method.patch'); + + $this->router->transOptions('localization::routes.methods.options', [ + 'as' => 'method.options', + function () { + return 'OPTIONS method'; + } + ]); + $this->setRouteName('method.options'); + + $this->router->transDelete('localization::routes.methods.delete', [ + 'as' => 'method.delete', + function () { + return 'DELETE method'; + } + ]); + $this->setRouteName('method.delete'); + + $this->router->transAny('localization::routes.methods.any', [ + 'as' => 'method.any', + function () { + return 'Any method'; + } + ]); + $this->setRouteName('method.any'); + + /* ------------------------------------------------------------------------------------------------ + | Resource Controller + | ------------------------------------------------------------------------------------------------ + */ + $this->router->resource('dummy', Controllers\DummyController::class); + $this->setRouteNames([ + 'dummy.index', + 'dummy.create', + 'dummy.store', + 'dummy.show', + 'dummy.edit', + 'dummy.update', + 'dummy.destroy', + ]); + + $this->router->group(['prefix' => 'foo'], function () { + $this->router->resource('bar', Controllers\BarController::class); + }); + + $this->setRouteNames([ + 'bar.index', + 'bar.create', + 'bar.store', + 'bar.show', + 'bar.edit', + 'bar.update', + 'bar.destroy', + ]); }); - $this->setRouteNames([ - 'foo.bar.index', - 'foo.bar.create', - 'foo.bar.store', - 'foo.bar.show', - 'foo.bar.edit', - 'foo.bar.update', - 'foo.bar.destroy', - ]); }); } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 0b0baf6..8518127 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,6 +1,6 @@