Modeling Multilingual Attributes in Laravel, a nice approach

Abdelrahman Hamada
Feb 12, 2019 · 4 min read

This guide will help Laravel developers support multilingual attributes in your model with a simple trait.

Suppose that you support Arabic and English languages in your application and the user must add his content with its translation, So in this case, How would you build it?

Maybe the first idea you think it is to check the language then determine what is the field will you use, for in blade Example: -

if(App::isLocale('ar'))
$title = $category->title_ar

else if(App::isLocale('fr'))
$title = $category->title_fr
else
$title = $category->title_en

@endif
//do anything with $title...

Oops!! We’ll need to apply the previous code for all attributes support two languages! and what if we wish to supports more languages?! no doubt this will be exhausting.

Now we need to make it as simple as possible without checking language every time? what if we use a field and set its content to change dynamically depending on the language of the user, and replacing the previous example with the following simple line: -

$title = $category->title;

Let’s say we have Category Model and it has title_ar and title_en fields, we will build trait so when we call $category->title it will return the title_ar or title_en depending on the user’s language.

As a Laravel developer, I think you should know PHP Magic Methods, especially __get magic method which we will rely on in this tutorial.

Laravel uses __get to handle model fields and mutators so it will get fields values from the database without your intervention.

Now I think you should know what is the requirement and have an idea of how to build it, let’s go!!!

Firstly, we will create the Publication Model and its migration in your Laravel project.

php artisan make:model Category -m

Note that we have added title_ar, title_en fields in the Category migration file, So it will be like the following code.

<?phpuse Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCategoriesTable extends Migration
{
/**
* Run the migrations.
*
*
@return void
*/
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('title_ar');
$table->string('title_en');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
*
@return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
}

Now in the model, We will define $multi_lang array attribute, which will have the attributes without the language suffix, and uses MultiLanguage Trait use MultiLanguage;” which we will define it in the next step.

<?phpnamespace App;use App\Traits\MultiLanguage;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use MultiLanguage;
protected $fillable = [
'title_en', 'title_ar',
];
/**
* This array will have the attributes which you want it to support multi languages
*/
protected $multi_lang = [
'title',
];
}

What now!! we will define a new trait which has the simple magic code, this trait overrides __get method from Laravel Model class that we will use in our code, When you call $category->title the “title” will be passed to __get as a $key parameter, and we will check if it is in the $multi_lang array?!

If yes, we will append $key with the user language, So if the language is Arabic $key will be tilte_ar and if it English the $key will be title_en, Then we will call the parent __get method with the edited value, so it will act as call $category->title_ar or $category->title_en depending on the language.

<?php
/**
* Created by PhpStorm.
* User: abed
* Date: 2/11/19
* Time: 4:04 PM
*/
namespace App\Traits;use Illuminate\Support\Facades\App;trait MultiLanguage
{
/**
*
@param string $key
*
@return mixed
*/
public function __get($key)
{
if (isset($this->multi_lang) && in_array($key, $this->multi_lang)) {
$key = $key . '_' . App::getLocale();
}
return parent::__get($key);
}
}

Now, Let’s create a UnitTest class to test our code.

php artisan make:test MultiLanguageTest --unit

In this test, we create an instance of Category and fill set the title_ar => “منشور” and title_en=>”Post”, Then we call the $mutli_lang property $category->title, Once when the language was Arabic, and once when it is English.

<?phpnamespace Tests\Unit;use App\Category;
use Illuminate\Support\Facades\App;
use Tests\TestCase;
class MultiLanguageTest extends TestCase
{
/**
* Test MutliLanguage Trait.
*
*
@return void
*/
public function testMultiLanguageAttribute()
{
$category = new Category;
$category->fill(['title_ar' => 'منشور', 'title_en' => 'Post']);
App::setLocale('ar');
$this->assertEquals($category->title, 'منشور');
App::setLocale('en');
$this->assertEquals($category->title, 'Post');
}
}

Now in your terminal, inside your project directory run the PHPUnit test.

./vendor/phpunit/phpunit/phpunit

Make sure you get OK as a result for your UnitTest, otherwise check that you’ve done everything correctly.

Finally, I hope you enjoyed and benefited from this article.

Special thanks to Osama for his great notes and additions.

Thanks to Sulaiman Radwan

Abdelrahman Hamada

Written by

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade