├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── Commands │ ├── RouteTranslationsCacheCommand.php │ ├── RouteTranslationsClearCommand.php │ └── RouteTranslationsListCommand.php ├── LaravelLocalization.php ├── LaravelLocalizationServiceProvider.php └── Traits │ ├── LoadsTranslatedCachedRoutes.php │ └── TranslatedRouteCommandContext.php └── stubs └── routes.stub /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = true 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.lock 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.9.9] - 2018-08-03 4 | 5 | Merged a [PR](https://github.com/czim/laravel-localization-route-cache/pull/17) that fixed an issue with root level paths when routes are cached. 6 | 7 | 8 | ## [0.9.8] - 2018-07-30 9 | 10 | Fixed issues with package auto-discovery and service provider loading order. 11 | 12 | 13 | ## [0.9.7] - 2018-07-28 14 | 15 | Added support for the language selector with cached routes. 16 | 17 | 18 | [0.9.9]: https://github.com/czim/laravel-localization-route-cache/compare/0.9.8...0.9.9 19 | [0.9.8]: https://github.com/czim/laravel-localization-route-cache/compare/0.9.7...0.9.8 20 | [0.9.7]: https://github.com/czim/laravel-localization-route-cache/compare/0.9.6...0.9.7 21 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Coen Zimmerman 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Translated Route Caching Solution for Laravel Localization 2 | 3 | [![Software License][ico-license]](LICENSE.md) 4 | 5 | **Important**: This solution has been merged into `mcamara/laravel-localization` since version `1.3.11`. 6 | This package is no longer required! 7 | 8 | 9 | 10 | A cobbled together fix to allow caching routes per locale for [mcamara's laravel localization](https://github.com/mcamara/laravel-localization). 11 | 12 | See the [github issue related to this fix](https://github.com/mcamara/laravel-localization/issues/201) in the original package. 13 | 14 | This has been tested with laravel `5.1` through `5.6`. 15 | 16 | 17 | ## Version Compatibility 18 | 19 | Laravel | Package 20 | :-------------|:-------- 21 | 5.1.x | 0.8.x 22 | 5.2.x and up | 0.9.x 23 | 24 | 25 | ## Change log 26 | 27 | [View the change log](CHANGELOG.md). 28 | 29 | ## Install 30 | 31 | Via Composer 32 | 33 | ``` bash 34 | $ composer require czim/laravel-localization-route-cache 35 | ``` 36 | 37 | If you don't use auto-discovery, add the service provider *after* mcamara's in your `config/app.php`: 38 | 39 | ``` php 40 | Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider::class, 41 | Czim\LaravelLocalizationRouteCache\LaravelLocalizationServiceProvider::class, 42 | ``` 43 | 44 | In your App's `RouteServiceProvider`, use the `LoadsTranslatedCachedRoutes` trait: 45 | 46 | ``` php 47 | class RouteServiceProvider extends ServiceProvider 48 | { 49 | use \Czim\LaravelLocalizationRouteCache\Traits\LoadsTranslatedCachedRoutes; 50 | ``` 51 | 52 | ## Usage 53 | 54 | To cache your routes, use 55 | 56 | ``` bash 57 | php artisan route:trans:cache 58 | ``` 59 | 60 | instead of the normal `route:cache` command. 61 | 62 | To list the routes for a given locale, use 63 | 64 | ``` bash 65 | php artisan route:trans:list {locale} 66 | 67 | # for instance: 68 | php artisan route:trans:list en 69 | ``` 70 | 71 | To clear cached routes for all locales, use 72 | 73 | ``` bash 74 | php artisan route:trans:clear 75 | ``` 76 | 77 | Note that using `route:clear` will also effectively unset the cache (at the minor cost of leaving some clutter in your bootstrap/cache directory). 78 | 79 | 80 | ## Credits 81 | 82 | - [Coen Zimmerman][link-author] 83 | - [All Contributors][link-contributors] 84 | 85 | ## License 86 | 87 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 88 | 89 | [ico-version]: https://img.shields.io/packagist/v/czim/laravel-localization-route-cache.svg?style=flat-square 90 | [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square 91 | [ico-downloads]: https://img.shields.io/packagist/dt/czim/laravel-localization-route-cache.svg?style=flat-square 92 | 93 | [link-packagist]: https://packagist.org/packages/czim/laravel-localization-route-cache 94 | [link-downloads]: https://packagist.org/packages/czim/laravel-localization-route-cache 95 | [link-author]: https://github.com/czim 96 | [link-contributors]: ../../contributors 97 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "czim/laravel-localization-route-cache", 3 | "description": "Translated route caching solution for laravel localization", 4 | "keywords": [ 5 | "localization", 6 | "translations", 7 | "route", 8 | "cache" 9 | ], 10 | "homepage": "https://github.com/czim/laravel-localization-route-cache", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Coen Zimmerman", 15 | "email": "coen@pixelindustries.com", 16 | "homepage": "http://www.pixelindustries.com", 17 | "role": "Developer" 18 | } 19 | ], 20 | "require": { 21 | "php": ">=5.5.9", 22 | "mcamara/laravel-localization": "^1.1" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit" : "4.*", 26 | "scrutinizer/ocular": "~1.1", 27 | "orchestra/testbench": "~3.0" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "Czim\\LaravelLocalizationRouteCache\\": "src" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Czim\\LaravelLocalizationRouteCache\\Test\\": "tests" 37 | } 38 | }, 39 | "scripts": { 40 | "test": "phpunit" 41 | }, 42 | "minimum-stability": "dev", 43 | "prefer-stable": true, 44 | "extra": { 45 | "laravel": { 46 | "providers": [ 47 | "Czim\\LaravelLocalizationRouteCache\\LaravelLocalizationServiceProvider" 48 | ] 49 | } 50 | }, 51 | "abandoned": true 52 | } 53 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | ./tests/ 16 | ./tests/TestCase.php 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Commands/RouteTranslationsCacheCommand.php: -------------------------------------------------------------------------------- 1 | files = $files; 42 | } 43 | 44 | /** 45 | * Execute the console command. 46 | */ 47 | public function handle() 48 | { 49 | $this->call('route:trans:clear'); 50 | 51 | $this->cacheRoutesPerLocale(); 52 | 53 | $this->info('Routes cached successfully for all locales!'); 54 | } 55 | 56 | /** 57 | * Cache the routes separately for each locale. 58 | */ 59 | protected function cacheRoutesPerLocale() 60 | { 61 | // Store the default routes cache, 62 | // this way the Application will detect that routes are cached. 63 | $allLocales = $this->getSupportedLocales(); 64 | 65 | array_push($allLocales, null); 66 | 67 | foreach ($allLocales as $locale) { 68 | 69 | $routes = $this->getFreshApplicationRoutes($locale); 70 | 71 | if (count($routes) == 0) { 72 | $this->error("Your application doesn't have any routes."); 73 | return; 74 | } 75 | 76 | foreach ($routes as $route) { 77 | $route->prepareForSerialization(); 78 | } 79 | 80 | $this->files->put( 81 | $this->makeLocaleRoutesPath($locale), $this->buildRouteCacheFile($routes) 82 | ); 83 | } 84 | } 85 | 86 | /** 87 | * Boot a fresh copy of the application and get the routes. 88 | * 89 | * @param string|null $locale 90 | * @return \Illuminate\Routing\RouteCollection 91 | */ 92 | protected function getFreshApplicationRoutes($locale = null) 93 | { 94 | $app = require $this->getBootstrapPath() . '/app.php'; 95 | 96 | if (null !== $locale) { 97 | 98 | $key = LaravelLocalization::ENV_ROUTE_KEY; 99 | 100 | putenv("{$key}={$locale}"); 101 | 102 | $app->make(Kernel::class)->bootstrap(); 103 | 104 | putenv("{$key}="); 105 | 106 | } else { 107 | 108 | $app->make(Kernel::class)->bootstrap(); 109 | } 110 | 111 | return $app['router']->getRoutes(); 112 | } 113 | 114 | /** 115 | * Build the route cache file. 116 | * 117 | * @param \Illuminate\Routing\RouteCollection $routes 118 | * @return string 119 | */ 120 | protected function buildRouteCacheFile(RouteCollection $routes) 121 | { 122 | $stub = $this->files->get( 123 | realpath( 124 | __DIR__ 125 | . DIRECTORY_SEPARATOR . '..' 126 | . DIRECTORY_SEPARATOR . '..' 127 | . DIRECTORY_SEPARATOR . 'stubs' 128 | . DIRECTORY_SEPARATOR . 'routes.stub' 129 | ) 130 | ); 131 | 132 | return str_replace( 133 | [ 134 | '{{routes}}', 135 | '{{translatedRoutes}}', 136 | ], 137 | [ 138 | base64_encode(serialize($routes)), 139 | $this->getLaravelLocalization()->getSerializedTranslatedRoutes(), 140 | ], 141 | $stub 142 | ); 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /src/Commands/RouteTranslationsClearCommand.php: -------------------------------------------------------------------------------- 1 | files = $files; 43 | } 44 | 45 | /** 46 | * Execute the console command. 47 | * 48 | * @return void 49 | */ 50 | public function handle() 51 | { 52 | foreach ($this->getSupportedLocales() as $locale) { 53 | 54 | $path = $this->makeLocaleRoutesPath($locale); 55 | 56 | if ($this->files->exists($path)) { 57 | $this->files->delete($path); 58 | } 59 | } 60 | 61 | $path = $this->laravel->getCachedRoutesPath(); 62 | 63 | if ($this->files->exists($path)) { 64 | $this->files->delete($path); 65 | } 66 | 67 | $this->info('Route caches for locales cleared!'); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/Commands/RouteTranslationsListCommand.php: -------------------------------------------------------------------------------- 1 | routes) == 0) { 31 | $this->error("Your application doesn't have any routes."); 32 | return; 33 | } 34 | 35 | $locale = $this->argument('locale'); 36 | 37 | if ( ! $this->isSupportedLocale($locale)) { 38 | $this->error("Unsupported locale: '{$locale}'."); 39 | return; 40 | } 41 | 42 | $this->routes = $this->getFreshApplicationRoutes($locale); 43 | 44 | $this->displayRoutes($this->getRoutes()); 45 | } 46 | 47 | /** 48 | * Boot a fresh copy of the application and get the routes. 49 | * 50 | * @param string $locale 51 | * @return \Illuminate\Routing\RouteCollection 52 | */ 53 | protected function getFreshApplicationRoutes($locale) 54 | { 55 | $app = require $this->getBootstrapPath() . '/app.php'; 56 | 57 | $key = LaravelLocalization::ENV_ROUTE_KEY; 58 | 59 | putenv("{$key}={$locale}"); 60 | 61 | $app->make(Kernel::class)->bootstrap(); 62 | 63 | putenv("{$key}="); 64 | 65 | return $app['router']->getRoutes(); 66 | } 67 | 68 | /** 69 | * Get the console command arguments. 70 | * 71 | * @return array 72 | */ 73 | protected function getArguments() 74 | { 75 | return [ 76 | ['locale', InputArgument::REQUIRED, 'The locale to list routes for.'], 77 | ]; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/LaravelLocalization.php: -------------------------------------------------------------------------------- 1 | request->segment(1); 24 | 25 | // If the locale is determined by env, use that 26 | // Note that this is how per-locale route caching is performed. 27 | if ( ! $locale) { 28 | $locale = $this->getForcedLocale(); 29 | } 30 | } 31 | 32 | if ( ! empty($this->supportedLocales[ $locale ])) { 33 | $this->currentLocale = $locale; 34 | } else { 35 | // if the first segment/locale passed is not valid 36 | // the system would ask which locale have to take 37 | // it could be taken by the browser 38 | // depending on your configuration 39 | 40 | $locale = null; 41 | 42 | // if we reached this point and hideDefaultLocaleInURL is true 43 | // we have to assume we are routing to a defaultLocale route. 44 | if ($this->hideDefaultLocaleInURL()) { 45 | $this->currentLocale = $this->defaultLocale; 46 | } else { 47 | // but if hideDefaultLocaleInURL is false, we have 48 | // to retrieve it from the browser... 49 | $this->currentLocale = $this->getCurrentLocale(); 50 | } 51 | } 52 | 53 | $this->app->setLocale($this->currentLocale); 54 | 55 | // The region/locale setlocale calls were not present in Mcamara's versions 56 | // for Laravel 5.0 and 5.1, so we'll skip it for those versions here as well. 57 | if ( ! preg_match('#^5\.[01]\.#', Application::VERSION)) { 58 | // Regional locale such as de_DE, so formatLocalized works in Carbon 59 | $regional = $this->getCurrentLocaleRegional(); 60 | 61 | if ($regional) { 62 | setlocale(LC_TIME, $regional . '.UTF-8'); 63 | setlocale(LC_MONETARY, $regional . '.UTF-8'); 64 | } 65 | } 66 | 67 | return $locale; 68 | } 69 | 70 | /** 71 | * Returns serialized translated routes for caching purposes. 72 | * 73 | * @return string 74 | */ 75 | public function getSerializedTranslatedRoutes() 76 | { 77 | return base64_encode(serialize($this->translatedRoutes)); 78 | } 79 | 80 | /** 81 | * Sets the translated routes list. 82 | * Only useful from a cached routes context. 83 | * 84 | * @param string $serializedRoutes 85 | */ 86 | public function setSerializedTranslatedRoutes($serializedRoutes) 87 | { 88 | if ( ! $serializedRoutes) { 89 | return; 90 | } 91 | 92 | $this->translatedRoutes = unserialize(base64_decode($serializedRoutes)); 93 | } 94 | 95 | /** 96 | * Returns the forced environment set route locale. 97 | * 98 | * @return string|null 99 | */ 100 | protected function getForcedLocale() 101 | { 102 | return env(static::ENV_ROUTE_KEY); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/LaravelLocalizationServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->singleton('laravellocalization', function () { 18 | return new LaravelLocalization(); 19 | }); 20 | } 21 | 22 | /** 23 | * Register any application services. 24 | */ 25 | public function register() 26 | { 27 | $this->registerCommands(); 28 | } 29 | 30 | /** 31 | * Registers route caching commands. 32 | */ 33 | protected function registerCommands() 34 | { 35 | $this->app->singleton('laravellocalizationroutecache.cache', Commands\RouteTranslationsCacheCommand::class); 36 | $this->app->singleton('laravellocalizationroutecache.clear', Commands\RouteTranslationsClearCommand::class); 37 | $this->app->singleton('laravellocalizationroutecache.list', Commands\RouteTranslationsListCommand::class); 38 | 39 | $this->commands([ 40 | 'laravellocalizationroutecache.cache', 41 | 'laravellocalizationroutecache.clear', 42 | 'laravellocalizationroutecache.list', 43 | ]); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/Traits/LoadsTranslatedCachedRoutes.php: -------------------------------------------------------------------------------- 1 | getLaravelLocalization(); 24 | 25 | $localization->setLocale(); 26 | 27 | $locale = $localization->getCurrentLocale(); 28 | 29 | $localeKeys = $localization->getSupportedLanguagesKeys(); 30 | 31 | // First, try to load the routes specifically cached for this locale 32 | // if they do not exist, write a warning to the log and load the default 33 | // routes instead. Note that this is guaranteed to exist, because the 34 | // 'cached routes' check in the Application checks its existence. 35 | 36 | $path = $this->makeLocaleRoutesPath($locale, $localeKeys); 37 | 38 | if ( ! file_exists($path)) { 39 | 40 | Log::warning("Routes cached, but no cached routes found for locale '{$locale}'!"); 41 | 42 | $path = $this->getDefaultCachedRoutePath(); 43 | } 44 | 45 | $this->app->booted(function () use ($path) { 46 | require $path; 47 | }); 48 | } 49 | 50 | /** 51 | * Returns the path to the cached routes file for a given locale. 52 | * 53 | * @param string $locale 54 | * @param string[] $localeKeys 55 | * @return string 56 | */ 57 | protected function makeLocaleRoutesPath($locale, $localeKeys) 58 | { 59 | $path = $this->getDefaultCachedRoutePath(); 60 | 61 | $localeSegment = request()->segment(1); 62 | if ( ! $localeSegment || ! in_array($localeSegment, $localeKeys)) { 63 | return $path; 64 | } 65 | 66 | return substr($path, 0, -4) . '_' . $locale . '.php'; 67 | } 68 | 69 | /** 70 | * Returns the path to the standard cached routes file. 71 | * 72 | * @return string 73 | */ 74 | protected function getDefaultCachedRoutePath() 75 | { 76 | return $this->app->getCachedRoutesPath(); 77 | } 78 | 79 | /** 80 | * @return \Mcamara\LaravelLocalization\LaravelLocalization 81 | */ 82 | protected function getLaravelLocalization() 83 | { 84 | return app('laravellocalization'); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/Traits/TranslatedRouteCommandContext.php: -------------------------------------------------------------------------------- 1 | getSupportedLocales()); 16 | } 17 | 18 | /** 19 | * @return string[] 20 | */ 21 | protected function getSupportedLocales() 22 | { 23 | return $this->getLaravelLocalization()->getSupportedLanguagesKeys(); 24 | } 25 | 26 | /** 27 | * @return \Mcamara\LaravelLocalization\LaravelLocalization 28 | */ 29 | protected function getLaravelLocalization() 30 | { 31 | return $this->laravel->make('laravellocalization'); 32 | } 33 | 34 | /** 35 | * @return string 36 | */ 37 | protected function getBootstrapPath() 38 | { 39 | if (method_exists($this->laravel, 'bootstrapPath')) { 40 | return $this->laravel->bootstrapPath(); 41 | } 42 | 43 | return $this->laravel->basePath() . DIRECTORY_SEPARATOR . 'bootstrap'; 44 | } 45 | 46 | /** 47 | * @param string $locale 48 | * @return string 49 | */ 50 | protected function makeLocaleRoutesPath($locale = '') 51 | { 52 | $path = $this->laravel->getCachedRoutesPath(); 53 | 54 | if ( ! $locale ) { 55 | return $path; 56 | } 57 | 58 | return substr($path, 0, -4) . '_' . $locale . '.php'; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /stubs/routes.stub: -------------------------------------------------------------------------------- 1 | setRoutes( 17 | unserialize(base64_decode('{{routes}}')) 18 | ); 19 | 20 | app('laravellocalization')->setSerializedTranslatedRoutes('{{translatedRoutes}}'); 21 | --------------------------------------------------------------------------------