How to Add Multiple Language to Eloquent Models in Laravel | Astrotomic Laravel Translatable

By Super Admin | Jun 03, 2022 | Laravel
Share :

https://www.fundaofwebit.com/post/how-to-add-multi-language-to-models-in-laravel

How to Add Multiple Language to Eloquent Models in Laravel | Astrotomic Laravel Translatable

Astrotomic Laravel Translatable CRUD Operation.


In this tutorial, we will be seeing how to add multi language to eloquent models each tables (CRUD Operation). 


Step 1: Install Laravel via composer and run the following command.

$ composer create-project laravel/laravel laravelproject


Step 2: Setup your database connection in .env file

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=brochure
DB_USERNAME=root
DB_PASSWORD=


Step 3: Install the Astrotomic Laravel Translatable Package and run the following command.

$ composer require astrotomic/laravel-translatable


Step 4: Configuring Package.

Let’s back to terminal to finish our configuration and run the following command:

$ php artisan vendor:publish --tag=translatable


Step 5: Setup the languages going to use.

Open config/translatable.php where we determine what languages we are going to use.

In this example we will only use English, Arabic and Spanish. But you are free to use whichever and how many you want.

'locales' => [
    'en',
    'ar',
    'es',
],


Step 6: Setup the Migrations for translations by the following command

Lets take an example of Post.

$ php artisan make:migration create_posts_table

it will create a posts migration file and fill as below.

public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        // $table->string('title');
        // $table->string('description');
$table->string('slug');
        $table->tinyInteger('status')->default('0');
        $table->timestamps();
    });
}

create the posts translation migration with following command:

php artisan make:migration create_post_translations_table

Open post_translations_table and paste below code.

public function up()
{
    Schema::create('post_translations', function (Blueprint $table) {
        $table->id();
        $table->unsignedBigInteger('post_id');
        $table->string('locale')->index();

        // Main table columns
        $table->string('title');
        $table->longText('description');

        // Setting two columns as unique
        $table->unique(['post_id', 'locale'], 'post_locale');

        // Setting foreign key
        $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
    });
}


Step 7: Setup Model (Laravel Eloquent Model).

Create Post model with following command:

php artisan make:model Post

Open "Post" Model in following path: app/Models/Post.php and paste below code.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

use Astrotomic\Translatable\Contracts\Translatable as TranslatableContract;
use Astrotomic\Translatable\Translatable;

class Post extends Model implements TranslatableContract
{
    use HasFactory, Translatable;

    protected $table = 'posts';

    public $translatedAttributes = ['title','description'];

    protected $fillable = [
        // 'title',
        // 'description',
        'slug',
    ];
}


Now, Lets create PostTranslation Model with the following command:

php artisan make:model PostTranslation
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class PostTranslation extends Model
{
    use HasFactory;

    protected $table = 'post_translations';

    protected $fillable = [
        'title',
        'description',
    ];

    public $timestamps = false;
}


Step 8: Create View (blade files).

Now we will prepare our resources/views/admin/posts/create.blade.php file for creating our freshly made multi-language post. We are  using "Bootstrap 5" for designing this user interface.

<div class="container">
    <ul class="nav nav-tabs" id="myTab" role="tablist">
        <li class="nav-item" role="presentation">
            <button class="nav-link active" id="englishTab" data-bs-toggle="tab" data-bs-target="#englishTab-pane" type="button" role="tab" aria-controls="englishTab-pane" aria-selected="true">
                English (EN)
            </button>
        </li>
        <li class="nav-item" role="presentation">
        <button class="nav-link" id="arabicTab" data-bs-toggle="tab" data-bs-target="#arabicTab-pane" type="button" role="tab" aria-controls="arabicTab-pane" aria-selected="false">
            Arabic (AR)
        </button>
        </li>
    </ul>

    <form action="{{ url('admin/posts') }}" method="POST">
        @csrf
        <div class="tab-content p-3 border" id="myTabContent">
            <div class="tab-pane fade show active" id="englishTab-pane" role="tabpanel" aria-labelledby="englishTab" tabindex="0">
                <div class="mb-3">
                    <label>Title (EN)</label>
                    <input type="text" name="en_title" class="form-control" />
                    @if($errors->has('en_title'))<div class="text-danger">{{ $errors->first('en_title') }}</div>@endif
                </div>
                <div class="mb-3">
                    <label>Description (EN)</label>
                    <textarea name="en_description" class="form-control" rows="4"></textarea>
                    @if($errors->has('en_description'))<div class="text-danger">{{ $errors->first('en_description') }}</div>@endif
                </div>
            </div>
            <div class="tab-pane fade" id="arabicTab-pane" role="tabpanel" aria-labelledby="arabicTab" tabindex="0">
                <div class="mb-3">
                    <label>Title (AR)</label>
                    <input type="text" name="ar_title" class="form-control" />
                    @if($errors->has('ar_title'))<div class="text-danger">{{ $errors->first('ar_title') }}</div>@endif
                </div>
                <div class="mb-3">
                    <label>Description (AR)</label>
                    <textarea name="ar_description" class="form-control" rows="4"></textarea>
                    @if($errors->has('ar_description'))<div class="text-danger">{{ $errors->first('ar_description') }}</div>@endif
                </div>
            </div>
            <div class="mb-3">
                <button type="submit" class="btn btn-primary">Save</button>
            </div>
        </div>
    </form>
</div>

Notice: The input fields names are prefixed by language code or sign like en_title, ar_title, where will be using to save data into database with different language.


Now, lets create resources/views/admin/posts/edit.blade.php file which is same as create.blade.php file. 

fetch the data from controller and display in edit.blade.php file as follows:

<!-- English (EN) -->
<input type="text" name="en_title" value="{{ $article->translate('en')->title }}" class="form-control" />
<textarea name="en_description" class="form-control" rows="4">{{ $article->translate('en')->description }}</textarea>

<!-- Arabic (AR) -->
<input type="text" name="ar_title" value="{{ $article->translate('ar')->title }}" class="form-control" />
<textarea name="ar_description" class="form-control" rows="4">{{ $article->translate('ar')->description }}</textarea>


Step 9: Saving or Updating the translations in Controller.

Let's go to the specific controller at store() method: 

public function store(Request $request)
{
    $postData = [
        'slug' => Str::slug($request->title),
        'en' => [
            'title' => $request->en_title,
            'description' => $request->en_description
        ],
        'ar' => [
            'title' => $request->ar_title,
            'description' => $request->ar_description
        ],
    ];
    Post::create($postData);

    return redirect('admin/posts')->with('message','Post Created');
}


Now, lets go to update() method:

public function update(int $id, Request $request)
{
    $postData = [
        'slug' => Str::slug($request->title),
        'en' => [
            'title' => $request->en_title,
            'description' => $request->en_description
        ],
        'ar' => [
            'title' => $request->ar_title,
            'description' => $request->ar_description
        ],
    ];

    $post = Post::findOrFail($id);
    $post->update($postData);

    return redirect('admin/posts')->with('message','Post Updated');
}


Frontend Side - Laravel localization. 

How to change the language and view the Posts in different language.

Step 1: Add languages available in config/app.php file as follows:

'languages' => [
    'en' => 'English',
    'ar' => 'Arabic',
    'es' => 'Spanish',
],


Step 2: Switching locales in Laravel

Method 1: To Change language using Route.

Route::get('/change-language/{locale}', function ($locale = null) {

    if (isset($locale) && in_array($locale, config('app.languages'))) {
        app()->setLocale($locale);
    }
   
    return redirect()->back();
});

To change the language, add the language or locale code at the end of url as shown below: 

Demo : http://localhost:8000/change-language/ar    (en=English, ar=Arabic, es=Spanish) - You can set one language at a time.


Method 2: To Change language using Parameter.

Paste the below dropdown in your navbar or anywhere as per your requirement.

@if(count(config('app.languages')) > 1)
<div class="dropdown">
    <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
        {{ strtoupper(app()->getLocale()) }}
    </button>
    <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
        @foreach(config('app.languages') as $langLocale => $langName)
        <li>
            <a class="dropdown-item" href="{{ url()->current() }}?change_language={{ $langLocale }}">
                {{ strtoupper($langLocale) }} ({{ $langName }})
            </a>
        </li>
        @endforeach
    </ul>
</div>
@endif


Now, create a Middleware named Localization with the following command:

php artisan make:middleware Localization

and paste below code in following path: app/Http/Middleware/Localization.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class Localization
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle(Request $request, Closure $next)
    {
        $languages = array_keys(config('app.languages'));
        $route = $request->route();

        if (request('change_language')) {
            session()->put('language', request('change_language'));
            $language = request('change_language');
            if (array_key_exists('locale', $route->parameters) && $route->parameters['locale'] != $language)
            {
                $route->parameters['locale'] = $language;

                if (in_array($language, $languages)) {
                    app()->setLocale($language);
                }

                return redirect(route($route->getName(), $route->parameters));
            }
        } elseif (session('language')) {
            $language = session('language');

            if (array_key_exists('locale', $route->parameters) && $route->parameters['locale'] != $language && in_array($route->parameters['locale'], $languages))
            {
                $language = $route->parameters['locale'];
                session()->put('language', $language);
            }
        } elseif (config('app.locale')) {
            $language = config('app.locale');
        }

        if (isset($language) && in_array($language, $languages)) {
            app()->setLocale($language);
        }

        return $next($request);
    }
}


Register this above Localization Middleware in kernel.php as given below:

protected $middlewareGroups = [
    'web' => [
        ...
        \App\Http\Middleware\Localization::class,
    ],
];


Step 3: Now you can fetch the posts with multi-language by following below given syntax.

<h3>{{ __($post->title) }}</h3>
<p>
    {!! __($post->description) !!}
</p>


That's it. Now, change the language to display multi-language.


Thanks for reading.

https://www.fundaofwebit.com/post/how-to-add-multi-language-to-models-in-laravel

Share this blog on social platforms