Skip to content

Commit

Permalink
Add translatable route parameters (#676)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
iwasherefirst2 authored and Marc Cámara committed Nov 4, 2019
1 parent 72a2285 commit 1497c94
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 52 deletions.
82 changes: 34 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,53 +358,8 @@ Note that Route Model Binding is supported.

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:

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

```php
<?php namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel {
/**
* The application's route middleware.
*
* @var array
*/
protected $routeMiddleware = [
/**** OTHER MIDDLEWARE ****/
'localize' => 'Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRoutes',
// TRANSLATE ROUTES MIDDLEWARE
];
}
```

```php
// app/Http/routes.php

Route::group(
[
'prefix' => LaravelLocalization::setLocale(),
'middleware' => [ 'localize' ] // Route translate middleware
],
function() {
/** ADD ALL LOCALIZED ROUTES INSIDE THIS GROUP **/
Route::get('/', function() {
// This routes is useless to translate
return View::make('hello');
});

Route::get(LaravelLocalization::transRoute('routes.about'), function() {
return View::make('about');
});

Route::get(LaravelLocalization::transRoute('routes.view'), function($id) {
return View::make('view',['id'=>$id]);
});
});

/** OTHER PAGES THAT SHOULD NOT BE LOCALIZED **/
```
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.

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:
Expand All @@ -427,6 +382,30 @@ return [

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.

### Translatable route parameters

You may use translatable slugs for your model, for example like this:

http://url/en/view/five
http://url/es/ver/cinco

For this, your model needs to implement `\Mcamara\LaravelLocalization\Interfaces\LocalizedUrlRoutable`.
The function `getLocalizedRouteKey($locale)` must return for a given locale the translated slug.
This is necessary so that your urls will be correctly [localized](#localized-urls).

Also, to use [route-model-binding](https://laravel.com/docs/routing#route-model-binding), you should overwrite the function `resolveRouteBinding($value)`
in your model. The function should return the model that belongs to the translated slug `$value`.
For example:

```php
public function resolveRouteBinding($value)
{
return static::findByLocalizedSlug($value)->first() ?? abort(404);
}
```



## Events

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:
Expand All @@ -444,9 +423,16 @@ Be sure to pass the locale and the attributes as parameters to the closure. You

## Caching routes

More information on support on [cached (translated) routes here](CACHING.md).
To cache your routes, use:

``` bash
php artisan route:trans:cache
```

... instead of the normal `route:cache` command.


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

## Common Issues

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Mcamara\LaravelLocalization\Interfaces;

interface LocalizedUrlRoutable
{
/**
* Get the value of the model's localized route key.
*
* @return mixed
*/
public function getLocalizedRouteKey($locale);
}
11 changes: 7 additions & 4 deletions src/Mcamara/LaravelLocalization/LaravelLocalization.php
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ public function getURLFromRouteNameTranslated($locale, $transKeyName, $attribute
$translation = $this->translator->get($transKeyName, [], $locale);
$route .= '/'.$translation;

$route = $this->substituteAttributesInRoute($attributes, $route);
$route = $this->substituteAttributesInRoute($attributes, $route, $locale);
}

if (empty($route)) {
Expand Down Expand Up @@ -635,10 +635,13 @@ public function checkLocaleInSupportedLocales($locale)
*
* @return string route with attributes changed
*/
protected function substituteAttributesInRoute($attributes, $route)
protected function substituteAttributesInRoute($attributes, $route, $locale = null)
{
foreach ($attributes as $key => $value) {
if ($value instanceOf UrlRoutable) {
if ($value instanceOf Interfaces\LocalizedUrlRoutable) {
$value = $value->getLocalizedRouteKey($locale);
}
elseif ($value instanceOf UrlRoutable) {
$value = $value->getRouteKey();
}
$route = str_replace(array('{'.$key.'}', '{'.$key.'?}'), $value, $route);
Expand Down Expand Up @@ -701,7 +704,7 @@ public function getRouteNameFromAPath($path)
$path = trim(str_replace('/'.$this->currentLocale.'/', '', $path), "/");

foreach ($this->translatedRoutes as $route) {
if (trim($this->substituteAttributesInRoute($attributes, $this->translator->get($route)), '/') === $path) {
if (trim($this->substituteAttributesInRoute($attributes, $this->translator->get($route), $this->currentLocale), '/') === $path) {
return $route;
}
}
Expand Down
15 changes: 15 additions & 0 deletions tests/LocalizerTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,21 @@ public function testGetURLFromRouteNameTranslated()
);
}

public function testLocalizedParameterFromTranslateUrl()
{
$model = new ModelWithTranslatableRoutes();

$this->assertEquals(
$this->test_url.'en/view/company',
app('laravellocalization')->getURLFromRouteNameTranslated('en', 'LaravelLocalization::routes.view', ['id' => $model])
);

$this->assertEquals(
$this->test_url.'es/ver/empresa',
app('laravellocalization')->getURLFromRouteNameTranslated('es', 'LaravelLocalization::routes.view', ['id' => $model])
);
}

public function testGetNonLocalizedURL()
{
$this->assertEquals(
Expand Down
16 changes: 16 additions & 0 deletions tests/ModelWithTranslatableRoutes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

use Illuminate\Database\Eloquent\Model;
use Mcamara\LaravelLocalization\Interfaces\LocalizedUrlRoutable;

class ModelWithTranslatableRoutes extends Model implements LocalizedUrlRoutable
{
public function getLocalizedRouteKey($locale)
{
if($locale == 'es'){
return 'empresa';
}

return 'company';
}
}

0 comments on commit 1497c94

Please sign in to comment.