Laravel 5.7 Multi-language | Complete guide

Find out more

1Fabio

Laravel 5.7 Multi-language | Complete guide

The password reset issue

In this guide I will cover all the steps to make a Laravel multi-language web application, including extra steps required to fix a couple of issues that I found along the way. However, I won’t cover the basics like how to install laravel or the basics of the authentication provided by the framework that you find visiting the official documentation page available on Laravel.com
Let’s get started, here is the guide index, you can jump directly into the part that you need if you want:

Step 1 – Group all routes and add a redirect route outside the group

Step 2 – Make a new SetLocale Middleware

Step 3 – Add the locale to all links of the views

Step 4 – Overriding the Auth/Controllers redirectTo properties

Step 5 – Add languages dropdown menu

Step 6 – Overriding the showResetForm method in the ResetPasswordController  

Step 7 – Override the Password Reset notification

Step 8 – Get started with Translations


 

Step 1 – Group all routes

The first step is move all routes inside a route group, visit your route file in routes/web.php

Route::group(
[
'prefix' => '{locale}',
'where' => ['locale' => '[a-zA-Z]{2}'],
'middleware' => 'setLocale'
],
function () {
// Move all your routes here
}
);
// Add a Redirect route outside the group
Route::get('/', function () {
return redirect(app()->getLocale());
});


Step 2 – Make a new setLocale Middleware

Now using the make artisan command we generate a new middleware for our locale
php artisan make:middleware setLocale

The new setLocale class will be available at app/Http/Middleware/setLocale.php and it should look like
class setLocale
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
app()->setLocale($request->segment(1));
return $next($request);
}
}

Now we need to register it in our app/Http/Kernel.php file inside the $routeMiddleware array
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'setLocale' => \App\Http\Middleware\setLocale::class,
];

We have already added the setLocale middleware to our route group in Step 1 so we are all set here.


Step 3 – Add the locale to all links of the views

Now most views like Register and Login won’t work as we didn’t pass the locale to any link or form action yet. We can do so using the add()->getLocale(), also assigning a name all our routes.
For example our login form action at resources/views/auth/login.blade.php should be changed like so:

form action="{{ route('login', app()->getLocale()) }}" method="POST"

Same thing to do in the section that follows for the reset link on the login form and all other links in the registration route, navbar menu and pages.

a class="btn btn-link" href="{{ route('password.request', app()->getLocale()) }}"

Remember to add a name to each route like so:
Route::get('/', function () {
return view('welcome'));
})->name('welcome');


Step 4 – Overriding the Auth/Controllers redirectTo properties

Now we need to update our auth controllers’ to redirect the user properly, for example in our app/Http/Controllers/Auth/LoginController.php to override the redirect property we can use the redirectTo method like so:

/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/home';
public function redirectTo()
{
return app()->getLocale() . '/home';
}

We need to do the same inside the app/Http/Controllers/Auth/RegisterController.php, app/Http/Controllers/Auth/ResetPasswordController.php, and app/Http/Controllers/Auth/VerificationController.php.


Step 5 – Add languages dropdown menu

Now in our navbar blade template we can add a dropdown menu to display a list of languages

First update our config/app.php file to include our languages array:

/*
|--------------------------------------------------------------------------
| Application Locale Configuration
|--------------------------------------------------------------------------
|
| The application locale determines the default locale that will be used
| by the translation service provider. You are free to set this value
| to any of the locales which will be supported by the application.
|
*/
'locale' => 'en',
'availableLocale' => [
'en',
'it'
],

Above I ave added only English and Italian, but you can add more.

Now inside our layouts/app.blade.php inside the the top menu we can add a drop down menu to display a list of languages:


Step 6 – Overriding the showResetForm method in the ResetPasswordController

 

While working on this Laravel Multi-language project I found two main issues that prevented the password reset views and email to work as expected.

  1. On the reset.blade.php view, the request returns the locale “en” instead of the password reset token value.
  2. In the email body the link structure of the button is incorrect.

Issue 1:
If you do dd($request->all()) on the ResetPasswordController@reset method this is what you will get:

array:5 [▼
“_token” => “YrwPp06e6dV3iVlyQ59y1lvcNvOwCoQr0bIyAwgX”
“token” => “en”
“email” => “mail@admin.com”
“password” => “password”
“password_confirmation” => “password”
]

The value on the token input element on the reset.blade.php template contains the value of the locale instead of the value of the token when you inspect it via chrome dev tools.

For the Issue two:

The structure of the reset link inside the email body is formatted like so: localhost/long_token_string_here/password/reset, instead of localhost:8000/en/password/reset/long_token_string_here

This are were the routes

Route::group(
[
‘prefix’ => ‘{locale}’,
‘where’ => [‘locale’ => ‘[a-zA-Z]{2}’],
‘middleware’ => ‘setLocale’
],
function () {
Route::get(‘/password/email/’, ‘Auth\ForgotPasswordController@showLinkRequestForm’)->name(‘password.email’);
Route::post(‘/password/email/’, ‘Auth\ForgotPasswordController@sendResetLinkEmail’)->name(‘password.email’);
Route::get(‘/password/reset/{token}’, ‘Auth\ResetPasswordController@showResetForm’)->name(‘password.reset’);
Route::post(‘/password/reset/’, ‘Auth\ResetPasswordController@reset’)->name(‘password.reset’);
});

The fist issue is solved by Changing the showResetForm method from:

public function showResetForm(Request $request, $token = null)
{
return view('auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
}

To:

public function showResetForm(Request $request, $token = null)
{
$token = $request->token;
return view('auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
}

Step 7 – Override the Password Reset notification

For the second issue we need to override the password reset notification as follow:

To adjust the link of the button inside the password reset email body we need to:

  1. make a new password reset notification class
  2. Edit the ResetPassword notification class and its constructor to accept the token
  3. Overide the method on the user model

Let’s start by making a new notification class using the following artisan command:

php artisan make:notification ResetPassword

Then we modify the file in app/Notifications/ResetPassword.php in the following way:

use Illuminate\Auth\Notifications\ResetPassword as ResetPasswordNotification;
Above we import the new ResetPassword notification class then change class in the following way, adding the extends ResetPasswordNotification and token inside the construct like so:

class ResetPassword extends ResetPasswordNotification
{
use Queueable;
public $token;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($token)
{
$this->token = $token;
}

Continuing in the same file, we need to edit the toMail method like so:

/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$locale = app()->getLocale();
return (new MailMessage)
->subject('Reset your password - ' . config('app.name'))
->line('Hey this email was sent to you because you requested a password change for your order.')
->action('Reset Password', url($locale . '/password/reset', $this->token))
->line(' if you did not request a password change, please ignore this email.');
}

Now we need to override the method sendPasswordResetNotification inside the User class, in the file app/Http/User.php

First we Import the new ResetPassword class at the top

use App\Notifications\ResetPassword;

Then we Override the method

public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPassword($token));
}


Step 8 – Get started with Translations

We can now start translating our contents in different languages but adding a json file with all required strings that we want to translate.

each string of text in your blade templates files must be wrapped like so:  __(” text to translate “) to make this work. Make sure you use double quotes if the string contains a single quote, ie. __(“That’s my string”) must be wrapped using double quotes and not with single quotes like __(‘That’s a string’) otherwise it won’t work.

then inside resources/lang/en.json file we can add our translations. For each language we make a new json file, for instance if you want to translate to italian you will need to add an it.json file inside the resources/lang folder.

{"Register": "Registrati",
"Complete all fields marked with": "Completa tutti i campi marcati con un",
"Profile": "Profilo",
"User Type": "Typo di Utente",
"Upload Your Profile Image": "Carca un immagine profilo",
"Company Name": "Nome Azienda",
"Profession": "Professione",
"Website Url": "Sito Web",
"Account": "Account",
"Full Name": "Nome Completo",
"Phone Number": "Numero di telefono",
"Confirm Password": "Conferma la Password",}

 


Sources:

https://laraveldaily.com/multi-language-routes-and-locales-with-auth/

https://tech.fleka.me/translate-laravels-reset-password-email-b0f1d6e4709a

https://medium.com/@mrciovdias/nice-post-dude-7374ffae2b34


The Author

Written by:

I am a senior entrepreneur, full-stack php developer, WordPress, Magento experience with knowledge responsive web design, frameworks and SEO techniques. Several years of experience as CAD Designer and website-eCommerce administrator with digital marketing experience. Analytical mindset with problem solving skills. Productive, self motivated and well organised. I’m a bilingual Italian-English with a strong personality, very flexible, and enthusiastic to work in other Cities or Countries. Loving knowledge and new challenges if there is anything that I don’t know how to do, I’m always likely to learn it. I put passion and care in everything I do. I’ve a strong sense of responsibility, ethics and duty. I’m a friendly, enthusiastic open minded person, always happy to work in a team but also capable of working on my own.


Related Posts

Mobile application development with flutter

Build Mobile Apps With Flutter

Multi-language-laravel

Laravel 5.7 Multi-language | Complete guide

Dashboard Virtualmin

How to build your own web hosting server using Virtualmin, Ubuntu 18.04 and Vitualbox in 40 Minutes.


Comments

Leave a comment

Your email address will not be published. Required fields are marked *


Need Help?

Just get in touch! I'm always happy to help.


Get professional advice today on a wide range of solutions for your business.

Contact Fabio