diff --git a/composer.json b/composer.json index 33623e8..b5dd44b 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ "license": "MIT", "require": { "php": "^8.2", - "codedor/laravel-locale-collection": "^0.0.2", + "codedor/laravel-locale-collection": "^0.0.3", "illuminate/contracts": "^10.0", "spatie/laravel-package-tools": "^1.12" }, diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 61a2df4..3e5f508 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,14 +1,11 @@ - + tests - - ./src - @@ -21,4 +18,9 @@ + + + ./src + + diff --git a/src/Providers/TranslatableRoutesServiceProvider.php b/src/Providers/TranslatableRoutesServiceProvider.php index c841ae0..5a18ec8 100644 --- a/src/Providers/TranslatableRoutesServiceProvider.php +++ b/src/Providers/TranslatableRoutesServiceProvider.php @@ -8,6 +8,7 @@ use Codedor\TranslatableRoutes\TranslateRoute; use Illuminate\Routing\Route as RoutingRoute; use Illuminate\Support\Facades\Route; +use Illuminate\Support\Str; use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; @@ -22,19 +23,25 @@ public function configurePackage(Package $package): void public function bootingPackage() { + Locale::macro('routePrefix', function (): string { + /** @var Locale $this */ + return Str::lower($this->locale()); + }); + LocaleCollection::macro('registerRoutes', function (Closure|array|string $callback): void { /** @var LocaleCollection $this */ $this->each(fn (Locale $locale) => Route::middleware('translatable') ->domain($locale->url()) - ->where(['locale' => $locale->locale()]) + ->where(['translatable_prefix' => $locale->routePrefix()]) ->prefix('/' . $locale->urlLocale()) + ->as($locale->routePrefix() . '.') ->group($callback) ); collect(Route::getRoutes()->getRoutes()) ->filter(fn (RoutingRoute $route) => in_array('translatable', $route->middleware())) ->each(function (RoutingRoute $route) { - $locale = $this->firstLocale($route->wheres['locale'] ?? ''); + $locale = $this->firstWhere(fn (Locale $locale) => Str::startsWith($route->getName(), $locale->routePrefix())); if (! $locale) { return; diff --git a/src/TranslateRoute.php b/src/TranslateRoute.php index 54ede43..fb85d98 100644 --- a/src/TranslateRoute.php +++ b/src/TranslateRoute.php @@ -7,12 +7,11 @@ use Codedor\LocaleCollection\LocaleCollection as TranslatableRoutesLocaleCollection; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Facades\Route; use Illuminate\Support\Str; class TranslateRoute { - public static function forName(string $routeName, string $locale = null, array|Collection $parameters = []): string + public static function forName(string $routeName, string $locale = null, array|Collection $parameters = []): ?string { if (! $locale) { $locale = app()->getLocale(); @@ -22,11 +21,16 @@ public static function forName(string $routeName, string $locale = null, array|C app('url')->forceRootUrl($localeObject->url()); - $route = collect(Route::getRoutes()->getRoutes()) - ->filter(fn ($route) => $route->getName() === $routeName && $route->wheres['locale'] === $locale) - ->first(); + try { + return route( + "{$localeObject->routePrefix()}.{$routeName}", + self::translateParameters($parameters, $localeObject) + ); + } catch (\Throwable $th) { + report($th); - return app('url')->toRoute($route, self::translateParameters($parameters, $localeObject), true); + return null; + } } public static function getAllForNameOrCurrent(string $routeName = null, array $parameters = []): TranslatableRoutesLocaleCollection diff --git a/src/helpers.php b/src/helpers.php index f3294b0..07d3d88 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -5,7 +5,7 @@ use Illuminate\Support\Collection; if (! function_exists('translate_route')) { - function translate_route(string $routeName, string $locale = null, array|Collection $parameters = []): string + function translate_route(string $routeName, string $locale = null, array|Collection $parameters = []): ?string { return TranslateRoute::forName($routeName, $locale, $parameters); } diff --git a/tests/Feature/LocaleCollectionTest.php b/tests/Feature/LocaleCollectionTest.php index 32db071..f54a988 100644 --- a/tests/Feature/LocaleCollectionTest.php +++ b/tests/Feature/LocaleCollectionTest.php @@ -29,10 +29,8 @@ ->getName()->toBe('non-translatable') ->wheres->toBe([]), fn ($route) => $route - ->getName()->toBe('home') - ->wheres->toBe(['locale' => 'nl-BE']), + ->getName()->toBe('nl-be.home'), fn ($route) => $route - ->getName()->toBe('home') - ->wheres->toBe(['locale' => 'fr-BE']) + ->getName()->toBe('fr-be.home') ); }); diff --git a/tests/Feature/RouteCompileTest.php b/tests/Feature/RouteCompileTest.php new file mode 100644 index 0000000..8f7f98d --- /dev/null +++ b/tests/Feature/RouteCompileTest.php @@ -0,0 +1,43 @@ +push(new Locale('fr-BE', 'http://codedor.be', 'fr')) + ->push(new Locale('en-GB', 'http://codedor.com')); + + LocaleCollection::registerRoutes(function () { + Route::get('', function () { + return translated_routes(); + })->name('home'); + + Route::get('/page/{page:slug}', function () { + return translated_routes(); + })->name('page'); + + Route::get('/category/{category}', function (TestCategory $category) { + return translated_routes(); + })->name('enum'); + }); + + $this->page = TestPage::first(); +}); + +// calling route:cache does not work in tests, so we have to test the compiled routes manually +it('can compile routes', function () { + $routes = tap(app('router')->getRoutes(), function ($routes) { + $routes->refreshNameLookups(); + $routes->refreshActionLookups(); + }); + + foreach ($routes as $route) { + $route->prepareForSerialization(); + } + + expect($routes->compile())->toBeArray(); +});