Supongamos que tenemos el siguiente problema. Necesitamos acceder a un array en el fichero de traducciones y sustituir los parámetros por su valor. Se trata de una estructura que va a tener siempre las mismas claves. Un ejemplo que nos encontramos a menudo es el texto con el que construimos un correo electrónico. Imagina el fichero message.php cuya ruta completa sería resources/lang/en/message.php
1 2 3 4 5 6 7 8 | return [ 'directForUser' => [ 'title' => 'Hola, :user' 'body' => 'Tienes un nuevo mensaje directo de :fromName' 'button' => 'Entra a leerlo' 'footer' => ':user' ] ] |
Si accedemos a tinker. Nos situamos con el terminal en la carpeta raíz de nuestro proyecto y ejecutamos:
1 | php artisan tinker |
Podemos pedir todo este array con una serie de valores definidos:
1 2 3 4 5 6 7 8 9 10 | >>> trans('message.directForUser', [ 'user' => 'Manuel', 'fromName' => 'Pepe', ]) => [ 'title' => 'Hola, :user' 'body' => 'Tienes un nuevo mensaje directo de :fromName' 'button' => 'Entra a leerlo' 'footer' => ':user' ] |
Cómo puedes comprobar, el efecto no es el deseado. Querríamos obtener el mismo array pero con los parámetros sustituidos por su valor. Veamos como conseguir este efecto.
Para ello usaremos dos superpoderes de Laravel. Las colecciones y las macros en colecciones.
Lo primero que debemos hacer es recorrer el array que nos devuelve la función trans. Esto se consigue convirtiendo el array en una colección con collect() y usando el método map:
1 2 3 4 5 6 | collect(trans('message.directForUser'))->map(function($text, $key) { return $message['$key'] = trans('message.directForUser' . '.' . $key, [ 'user' => 'Manuel', 'fromName' => 'Pepe', ]); }) |
Esto ya nos devuelve lo que queremos pero… es un poco díficil de recordar… ¿No?. Laravel nos permite esconder esta complejidad, si se puede generalizar, tras una macro. Pero antes vamos a cambiar un poco nuestro código.
Saquemos el nombre de la llave que queremos traducir fuera:
1 2 3 4 5 6 7 | $transKey = 'message.directForUser'; collect(trans($transKey))->map(function($text, $key) use ($transKey) { return $message['$key'] = trans($transKey . '.' . $key, [ 'user' => 'Manuel', 'fromName' => 'Pepe', ]); }) |
También podemos sacar fuera de este código el array con las traducciones:
1 2 3 4 5 6 7 8 | $transKey = 'message.directForUser'; $transParams = [ 'user' => 'Manuel', 'fromName' => 'Pepe', ]; collect(trans($transKey))->map(function($text, $key) use ($transKey, $transParams) { return $message['$key'] = trans($transKey . '.' . $key, $transParams); }) |
Y ya nos queda algo que podemos empezar a mirar como una macro. Vamos a crearla. Para ello entramos en app/Providers/AppServiceProvider.php y añadimos el siguiente código. Vamos a añadir también que lo que nos devuelva esta macro sea un array:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php ... use Illuminate\Support\Collection; class AppServiceProvider extends ServiceProvider { public function boot() { ... Collection::macro('transArray', function ($transKey, $transParams) { return $this->map(function ($value, $key) use ($transKey, $transParams) { return $message[$key] = trans($transKey . '.' . $key, $transParams); })->toArray(); }); } } |
Y ahora podemos hacer:
1 2 3 4 5 6 | $transKey = 'message.directForUser'; $transParams = [ 'user' => 'Manuel', 'fromName' => 'Pepe', ]; collect(trans($transKey))->transArray($transKey, $transParams); |
Podemos ocultar esto bajo una función en app/Helpers.php
1 2 3 4 5 6 7 8 | class Helpers { public function transArray($transKey, $transParams) { return collect(trans($transKey)) ->transArray($transKey, $transParams); } } |
y nuestro código quedaría ejecutado en tinker:
1 2 3 4 5 6 7 8 | use Facade\App\Helpers; $transKey = 'message.directForUser'; $transParams = [ 'user' => 'Manuel', 'fromName' => 'Pepe', ]; Helpers::transArray($transKey, $transParams); |
¿Te ha ayudado este post? ¿Tienes dudas? Te veo en los comentarios 😀