Skip to content

Commit 1497c94

Browse files
niels-numbersMarc Cámara
authored andcommitted
Add translatable route parameters (#676)
* Add new Interface for translating RouteParameter * Add instructions to use translatable route paramters * Add route-model-binding to translatable slugs * Correct Interface path in Readme * Fixes PSR2 for new test method * Update Readme Add example for route-model-binding
1 parent 72a2285 commit 1497c94

File tree

5 files changed

+85
-52
lines changed

5 files changed

+85
-52
lines changed

README.md

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -358,53 +358,8 @@ Note that Route Model Binding is supported.
358358

359359
You can adapt your URLs depending on the language you want to show them. For example, http://url/en/about and http://url/es/acerca (acerca is about in spanish) or http://url/en/view/5 and http://url/es/ver/5 (view == ver in spanish) would be redirected to the same controller using the proper filter and setting up the translation files as follows:
360360

361-
As it is a middleware, first you have to register in on your `app/Http/Kernel.php` file like this:
361+
It is necessary that the `localize` middleware in loaded in your `Route::group` middleware (See [installation instruction](#LaravelLocalizationRoutes)).
362362

363-
```php
364-
<?php namespace App\Http;
365-
366-
use Illuminate\Foundation\Http\Kernel as HttpKernel;
367-
368-
class Kernel extends HttpKernel {
369-
/**
370-
* The application's route middleware.
371-
*
372-
* @var array
373-
*/
374-
protected $routeMiddleware = [
375-
/**** OTHER MIDDLEWARE ****/
376-
'localize' => 'Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRoutes',
377-
// TRANSLATE ROUTES MIDDLEWARE
378-
];
379-
}
380-
```
381-
382-
```php
383-
// app/Http/routes.php
384-
385-
Route::group(
386-
[
387-
'prefix' => LaravelLocalization::setLocale(),
388-
'middleware' => [ 'localize' ] // Route translate middleware
389-
],
390-
function() {
391-
/** ADD ALL LOCALIZED ROUTES INSIDE THIS GROUP **/
392-
Route::get('/', function() {
393-
// This routes is useless to translate
394-
return View::make('hello');
395-
});
396-
397-
Route::get(LaravelLocalization::transRoute('routes.about'), function() {
398-
return View::make('about');
399-
});
400-
401-
Route::get(LaravelLocalization::transRoute('routes.view'), function($id) {
402-
return View::make('view',['id'=>$id]);
403-
});
404-
});
405-
406-
/** OTHER PAGES THAT SHOULD NOT BE LOCALIZED **/
407-
```
408363
In the routes file you just have to add the `LaravelLocalizationRoutes` filter and the `LaravelLocalization::transRoute` function to every route you want to translate using the translation key.
409364

410365
Then you have to create the translation files and add there every key you want to translate. I suggest to create a routes.php file inside your `resources/lang/language_abbreviation` folder. For the previous example, I have created two translations files, these two files would look like:
@@ -427,6 +382,30 @@ return [
427382

428383
Once files are saved, you can access to http://url/en/about , http://url/es/acerca , http://url/en/view/5 and http://url/es/ver/5 without any problem.
429384

385+
### Translatable route parameters
386+
387+
You may use translatable slugs for your model, for example like this:
388+
389+
http://url/en/view/five
390+
http://url/es/ver/cinco
391+
392+
For this, your model needs to implement `\Mcamara\LaravelLocalization\Interfaces\LocalizedUrlRoutable`.
393+
The function `getLocalizedRouteKey($locale)` must return for a given locale the translated slug.
394+
This is necessary so that your urls will be correctly [localized](#localized-urls).
395+
396+
Also, to use [route-model-binding](https://laravel.com/docs/routing#route-model-binding), you should overwrite the function `resolveRouteBinding($value)`
397+
in your model. The function should return the model that belongs to the translated slug `$value`.
398+
For example:
399+
400+
```php
401+
public function resolveRouteBinding($value)
402+
{
403+
return static::findByLocalizedSlug($value)->first() ?? abort(404);
404+
}
405+
```
406+
407+
408+
430409
## Events
431410

432411
You can capture the URL parameters during translation if you wish to translate them too. To do so, just create an event listener for the `routes.translation` event like so:
@@ -444,9 +423,16 @@ Be sure to pass the locale and the attributes as parameters to the closure. You
444423

445424
## Caching routes
446425

447-
More information on support on [cached (translated) routes here](CACHING.md).
426+
To cache your routes, use:
427+
428+
``` bash
429+
php artisan route:trans:cache
430+
```
431+
432+
... instead of the normal `route:cache` command.
433+
448434

449-
Note that the separate [czim/laravel-localization-route-cache](https://github.com/czim/laravel-localization-route-cache) package is no longer required.
435+
For more details see [here](CACHING.md).
450436

451437
## Common Issues
452438

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Mcamara\LaravelLocalization\Interfaces;
4+
5+
interface LocalizedUrlRoutable
6+
{
7+
/**
8+
* Get the value of the model's localized route key.
9+
*
10+
* @return mixed
11+
*/
12+
public function getLocalizedRouteKey($locale);
13+
}

src/Mcamara/LaravelLocalization/LaravelLocalization.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ public function getURLFromRouteNameTranslated($locale, $transKeyName, $attribute
379379
$translation = $this->translator->get($transKeyName, [], $locale);
380380
$route .= '/'.$translation;
381381

382-
$route = $this->substituteAttributesInRoute($attributes, $route);
382+
$route = $this->substituteAttributesInRoute($attributes, $route, $locale);
383383
}
384384

385385
if (empty($route)) {
@@ -635,10 +635,13 @@ public function checkLocaleInSupportedLocales($locale)
635635
*
636636
* @return string route with attributes changed
637637
*/
638-
protected function substituteAttributesInRoute($attributes, $route)
638+
protected function substituteAttributesInRoute($attributes, $route, $locale = null)
639639
{
640640
foreach ($attributes as $key => $value) {
641-
if ($value instanceOf UrlRoutable) {
641+
if ($value instanceOf Interfaces\LocalizedUrlRoutable) {
642+
$value = $value->getLocalizedRouteKey($locale);
643+
}
644+
elseif ($value instanceOf UrlRoutable) {
642645
$value = $value->getRouteKey();
643646
}
644647
$route = str_replace(array('{'.$key.'}', '{'.$key.'?}'), $value, $route);
@@ -701,7 +704,7 @@ public function getRouteNameFromAPath($path)
701704
$path = trim(str_replace('/'.$this->currentLocale.'/', '', $path), "/");
702705

703706
foreach ($this->translatedRoutes as $route) {
704-
if (trim($this->substituteAttributesInRoute($attributes, $this->translator->get($route)), '/') === $path) {
707+
if (trim($this->substituteAttributesInRoute($attributes, $this->translator->get($route), $this->currentLocale), '/') === $path) {
705708
return $route;
706709
}
707710
}

tests/LocalizerTests.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,21 @@ public function testGetURLFromRouteNameTranslated()
592592
);
593593
}
594594

595+
public function testLocalizedParameterFromTranslateUrl()
596+
{
597+
$model = new ModelWithTranslatableRoutes();
598+
599+
$this->assertEquals(
600+
$this->test_url.'en/view/company',
601+
app('laravellocalization')->getURLFromRouteNameTranslated('en', 'LaravelLocalization::routes.view', ['id' => $model])
602+
);
603+
604+
$this->assertEquals(
605+
$this->test_url.'es/ver/empresa',
606+
app('laravellocalization')->getURLFromRouteNameTranslated('es', 'LaravelLocalization::routes.view', ['id' => $model])
607+
);
608+
}
609+
595610
public function testGetNonLocalizedURL()
596611
{
597612
$this->assertEquals(

tests/ModelWithTranslatableRoutes.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
use Illuminate\Database\Eloquent\Model;
4+
use Mcamara\LaravelLocalization\Interfaces\LocalizedUrlRoutable;
5+
6+
class ModelWithTranslatableRoutes extends Model implements LocalizedUrlRoutable
7+
{
8+
public function getLocalizedRouteKey($locale)
9+
{
10+
if($locale == 'es'){
11+
return 'empresa';
12+
}
13+
14+
return 'company';
15+
}
16+
}

0 commit comments

Comments
 (0)