Translatable Trait
Hello, I'm developing a project where I need localization (the front end page must have 2 languages). For URL mapping and setting locales I'm using this package:
https://github.com/mcamara/laravel-localization
When it comes to translating model data I couldn't find a quick-and-easy package to use. The best one I found was:
https://github.com/dimsav/laravel-translatable
But it does much more then I need, and requires one table for each module to be translated. I developed my own trait to handle this and I would like the community input on it.
My goal is to keep accessing and setting $model->name and keeping all localization issues behind the scenes.
I've managed to achieve this with the following trait:
<?php
namespace App\Http\Traits;
use Illuminate\Database\Eloquent\Model;
use App\Models\Translation;
use \LaravelLocalization;
trait TranslatableTrait
{
public function __get($key)
{
if(isset($this->translatable) && in_array($key, $this->translatable))
{
//translate and return
return $this->getTranslation($key);
}
else
{
//don't translate, call parent
return parent::__get($key);
}
}
public function __set($key, $value)
{
if(isset($this->translatable) && in_array($key, $this->translatable))
{
//translate and return
$this->setTranslation($key,$value);
}
else
{
parent::__set($key, $value);
}
}
public function trans($key,$locale)
{
return $this->getTranslation($key,$locale);
}
public function getTranslation( $key, $locale = NULL )
{
if(!$locale)
{
$locale = LaravelLocalization::getCurrentLocale();
}
//model class, model id, locale code
$translation = Translation::where("model_class",get_class($this))->where("model_id",$this->id)->where("key",$key)->where("locale",$locale)->first();
if(!$translation)
{
return "";
}
else
{
return $translation->value;
}
}
public function setTranslation($key,$value,$locale = NULL)
{
if(!$locale)
{
$locale = LaravelLocalization::getCurrentLocale();
}
$translation = Translation::where("model_class",get_class($this))->where("model_id",$this->id)->where("key",$key)->where("locale",$locale)->first();
if(!$translation)
{
$translation = new Translation;
$translation->model_class = get_class($this);
$translation->model_id = $this->id;
$translation->key = $key;
$translation->locale = $locale;
$translation->value = $value;
}
else
{
$translation->value = $value;
}
return $translation->save();
}
public function toJson($locale = NULL)
{
if(!$locale)
{
$locale = LaravelLocalization::getCurrentLocale();
}
$array = $this->toArray();
if(isset($this->translatable))
{
foreach($this->translatable as $value)
{
$array[$value] = $this->getTranslation($value,$locale);
}
}
return json_encode($array);
}
}
To use this trait you need only one table:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTranslationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('translations', function (Blueprint $table) {
$table->increments('id');
$table->string('model_class');
$table->string('model_id');
$table->string('key');
$table->string('locale', 2);
$table->text('value');
$table->timestamps();
$table->unique(['model_class', 'model_id','locale','key']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('translations');
}
}
Then just import the Trait and set an array with the fields you need to translate to your modules and it's done.
use TranslatableTrait;
protected $translatable = ['name','description'];
The next step would be adding some tests and creating a package.
Do you think it will be usefull for someone else?
thanks!
ps.: I don't have any open source package, not sure the amount of work needed to keep one "live". I would also appreciate some input on that.
Please or to participate in this conversation.